目录
一、封装
1、私有变量
2、私有方法
3、使用属性
二、继承
2.1单继承:
2.2多继承
2.4方法的重写
三、多态
3.1 继承与多态
3.2 鸭子类型测试与多态
一、封装
封装性是面向对象重要的基本特性之一。封装隐藏了对象的内部细节,只保留有限的对外接口,外部调用者不用关心对象的内部细节,使得操作对象变得简单。
例如:一台计算机内部及其复杂,有主板,CPU,硬盘,内存等,而一般人不需要了解它的内部细节。计算机制造商用机箱把计算机封装起来,对外提供了一些接口,如鼠标,键盘,和显示器等,使用计算机就变得非常简单了。
1、私有变量
为了防止外部调用者随意存取类的内部数据(成员变量),内部数据(成员变量)会被封装成为“私有变量”,外部调用者只能通过方法调用私有变量。
默认情况下,Python中的变量是公有的,可以在类的外部访问它们。如果想让它们成为私有变量,则在变量前加上双下划线(__)即可。
示例:
- class Student(object):
- def __init__(self, name, age):
- self.name = name # 创建并初始化公有实例变量
- self.__age = age # 创建并初始化私有实例变量
-
- def print_info(self):
- print(f'姓名:{self.name},年龄:{self.__age}')
-
-
- student1 = Student("samual", 21)
- student1.print_info() # 打印名字和年龄出来
- print(student1.name) # 打印名字出来
- print(student1.__age) # 报错
私有变量可以在类的内部进行访问,不能在类的外部进行访问
2、私有方法
私有方法与私有变量的封装是类似的,在方法前面加上双下划线(__)就是私有方法了。
示例:
- class Student(object):
- def __init__(self, name, age):
- self.name = name # 创建并初始化公有实例变量
- self.__age = age # 创建并初始化私有实例变量
-
- def __print_info_inner(self): # 定义为私有方法
- print(f'姓名:{self.name},年龄:{self.__age}')
-
- def print_info_out(self):
- self.__print_info_inner() # 在类的内部调用私有方法
-
-
- student1 = Student("samual", 21)
- student1.print_info_out()
-
- student1.__print_info_inner() # 在外部调用私有方法会报错
3、使用属性
为了实现对象的封装,在一个类中不应该有公有的成员变量,这些成员变量应该都被设计成为私有的,然后通过公有的set(赋值)和get(取值)方法来访问。
示例:
- class Student(object):
- def __init__(self, name, age):
- self.name = name # 创建并初始化公有实例变量
- self.__age = age # 创建并初始化私有实例变量
-
- # 实例方法
- def print_info(self):
- print(f'姓名:{self.name},年龄:{self.__age}')
-
- # set方法
- def set_age(self,age):
- self.__age = age
-
- # get方法
- def get_age(self):
- return self.__age
-
-
- student1 = Student("samual", 21)
- student1.print_info()
- # 输出:姓名:samual,年龄:21
- student1.set_age(18)
- student1.print_info()
- # 输出:姓名:samual,年龄:18
在上面的示例中,当外部调用通过两个公有方法访问被封装的私有成员变量,会比较麻烦,所有我们还有一种简单的方法来访问私有变量,那个就是通过@property和@属性名.setter装饰器来完成。
示例:
- class Student(object):
- def __init__(self, name, age):
- self.name = name # 创建并初始化公有实例变量
- self.__age = age # 创建并初始化私有实例变量
-
- # 实例方法
- def print_info(self):
- print(f'姓名:{self.name},年龄:{self.__age}')
-
- @property
- def age(self): # 替代get_age(self)方法
- return self.__age
-
- @age.setter
- def age(self,age): # 替代set_age(self,age)方法
- self.__age = age
-
- student1 = Student("samual", 21)
- student1.print_info()
- student1.age = 18 # 通过属性赋值来修改
- student1.print_info()
二、继承
继承性也是面向对象重要的基本特性之一。
在现实世界中的继承关系无处不在,例如:猫与动物之间的关系:猫是一种特殊动物,具有动物的全部特征和行为,即数据和操作。在面向对象中动物是一般类,被称为“父类”,猫是特殊类,被称为“子类”。特殊类拥有一般类的全部数据和操作,可称子类继承父类。
在Python中声明子类继承父类的语法很简单,定义类时在类的后面使用一对小括号指定它的父类就可以了,在Python中一般类都继承object。
2.1单继承:
语法格式:
- class 父类(object):
- pass
-
- class 子类(Master):
- pass
示例:
- # 定义动物类
- class Animal(object):
- def __init__(self,name):
- self.name = name
-
- def print_info(self):
- print(f'动物的名字叫:{self.name}')
-
- # 定义猫类使其继承动物类
- class Cat(Animal):
- def __init__(self,name,age):
- Animal.__init__(self,name) # 调用父类的构造方法
- self.age = age
-
- cat = Cat('Tom',3)
- cat.print_info() # 父类的方法被子类继承,子类对象可调用
在调用父类的构造方法时,我们还有一种写法,那就是使用super()函数
super()
函数,它会使子类从其父继承所有方法和属性:
示例:
- class Cat(Animal):
- def __init__(self,name,age):
- super.__init__(name) # 调用父类的构造方法
- self.age = age
这种方法与用父类名调用的方法效果是一样的。
2.2多继承
一个类继承多个父类
在多继承中 如果多个父类中属性名 或者是方法名相同 那么将按照MRO算法查找
mro:
1.在自己的类中查找 如果找到 就结束
2.在父类元组中按照顺序查找 从左到右
类名.__mro__
所有在Python中,当子类继承多个父类时,如果在多个父类有相同的成员方法和成员变量,则子类优先继续左边父类中的成员方法或成员变量,从左到右继承级别从高到低。
语法格式:
- class A(Object):
- pass
-
- class B(object):
- pass
-
- class C(A,B):
- pass
示例:
- class Horse(object):
- def __init__(self,name):
- self.name = name
-
- def show_info(self):
- print(f'马的名字叫{self.name}')
-
- def run(self):
- print('马跑的很快')
-
- class Donkey(object):
- def __init__(self,name):
- self.name = name
-
- def show_info(self):
- print(f'驴的名字叫{self.name}')
-
- def run(self):
- print('驴跑的很慢')
-
- def roll(self):
- print('驴打滚')
-
- class Mule(Horse,Donkey):
- def __init__(self,name,age):
- super().__init__(name)
- self.age = age
- m = Mule('小骡',2)
- m.run() # 继承父类马方法
- m.roll() # 继承父类驴方法
- m.show_info() # 继承父类马方法
2.4方法的重写
如果子类的方法名与父类的方法名相同,则在这种情况下,子类的方法会重写父类的同名方法。
示例:
- class Horse(object):
- def __init__(self,name):
- self.name = name
-
- def show_info(self):
- print(f'马的名字叫{self.name}')
-
- def run(self):
- print('马跑的很快')
-
- class Donkey(object):
- def __init__(self,name):
- self.name = name
-
- def show_info(self):
- print(f'驴的名字叫{self.name}')
-
- def run(self):
- print('驴跑的很慢')
-
- def roll(self):
- print('驴打滚')
-
- class Mule(Horse,Donkey):
- def __init__(self,name,age):
- super().__init__(name)
- self.age = age
-
- def show_info(self):
- print(f'骡的名字叫{self.name},今年{self.age}岁')
-
- m = Mule('小骡',2)
- m.run() # 继承父类马方法
- m.roll() # 继承父类驴方法
- m.show_info() # 重写了父类马的方法
三、多态
多态也是面向对象重要的基本特征之一,“多态”指对象可以表现出多种形态。
例如:猫,狗,鸭子都属于动物,它们有“叫”和“动”等行为,但是它们叫的方式不同,动的方式也不同。
3.1 继承与多态
在多个子继承父类,并重写父类方法后,这些子继承所创建的对象之间就是多态的,这些对象采用不同的方式实现父类方法。
示例:
- class Animal(object):
- def speak(self):
- print('动物在叫,但不知道是哪种动物在叫')
-
-
- class Dog(Animal):
- def speak(self):
- print('狗:汪汪汪')
-
-
- class Cat(Animal):
- def speak(self):
- print('猫:喵喵喵')
-
- an1 = Dog()
- an2 = Cat()
- an1.speak()
- an2.speak()
3.2 鸭子类型测试与多态
Python的多态性更加灵活,支持鸭子类型测试。鸭子类型测试:指的是若看到一只鸟走起来像鸭子,游起来像鸭子,叫起来也像鸭子,那么这只鸟就可以被叫作鸭子。
由于支持鸭子类型测试,所有Python解释器不检测发生多态的对象是否继承同一个父类,只要它们有相同的行为(方法),它们之间就是多态的。
例如:我们设计一个函数start(),它接收具有“叫”speak() 方法的对象
- class Animal(object):
- def speak(self):
- print('动物在叫,但不知道是哪种动物在叫')
-
-
- class Dog(Animal):
- def speak(self):
- print('狗:汪汪汪')
-
-
- class Cat(Animal):
- def speak(self):
- print('猫:喵喵喵')
-
- class Car(object):
- def speak(self):
- print('汽车:嘀嘀嘀')
-
- def start(obj):
- obj.speak()
-
- start(Dog())
- start(Cat())
- start(Car())
上一章:Python中的面向对象