文章目录
1.继承
- 继承是面向对象的三大特性之一
- 通过继承我们可以使一个类获取到其他类中的属性和方法
- 在定义类时,可以在类名后面的括号中指定当前类的父类(超类、基类)
- 继承提高了类的复用性,让类与类之间产生了关系,有了这个关系,才有了多态的特性
# 这是一个动物类
class Animal:
def sleep(self):
print('动物会睡觉')
def run(self):
print('动物会跑')
# 狗继承了动物这个类
class Dog(Animal):
# pass # 占位
def speak(self):
print('汪汪汪')
d.run() # 动物会跑 继承了动物类中的方法
d.speak() # 汪汪汪
# isinstance() 用于检查一个实例不是一个类的实例,如果是则返回True
print(isinstance(d,Animal)) # True 在这里Dog类继承了Animal类,则Dog的实例也是其父类的实例
# issubclass() 用于检查一个类是否是另一个类的子类,如果这个类是另一个类的子类,返回True
print(issubclass(Dog,Animal)) # True
print(issubclass(Dog,object)) # True
print(issubclass(Animal,object)) # True
2.方法的重写
- 如果在子类中有和父类同名的方法,则通过子类实例去调用方法时,会调用子类的方法而不是父类的方法,这个特点我们称之为方法的重写(覆盖)
- 当我们调用一个对象的方法时:
• 会优先去当前对象中寻找是否具有该方法,如果有则直接调用
• 如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类中的方法
• 如果没有,则去父类中的父类寻找,以此类推,直到找到object,如果依然没有找到就报错了
class A(object):
def test(self):
print('A')
class B(A):
def test(self):
print('B')
class C(B):
pass
c = C()
c.test() # B 当前C类中没有test方法,则去其父类B中寻找,发现有则调用
3.super继承
- super()可以获取当前类的父类,并且通过super()返回对象调用父类方法时,不需要传递self
# 这是一个动物类
class Animal:
def __init__(self,name):
self._name = name
def sleep(self):
print('动物胡睡觉')
def run(self):
print('动物会跑')
@property
def new_name(self):
print('new_name的get方法执行了')
return self._name # 返回的是一个值
# setter方法 @属性名.setter
@new_name.setter
def new_name(self,name):
print('new_name的set方法执行了')
self._name = name
# 狗类继承了动物类
# 父类中所有的方法都会被继承,包括特殊方法
class Dog(Animal):
def __init__(self,name,age):
# self._name = name
# Animal.__init__(self,name) # 等价于self._name = name
# super()可以用来动态获取当前类的父类,不需要传递self
#(super(可以传self).__init__((此处不用传self)name))
super().__init__(name) # 等价于self._name = name
self._age = age # 这种类型只用于该类独有的,其余的父类中有的直接用上面super()就好
@property
def new_age(self):
print('new_age的get方法执行了')
return self._age # 返回的是一个值
# setter方法 @属性名.setter
@new_age.setter
def new_age(self,age):
print('new_age的set方法执行了')
self._age = age
def speak(self):
print('汪汪汪')
d = Dog('黑狗',5)
d.new_name = '田园犬' # new_name的set方法执行了
d.new_age = 6 # new_age的set方法执行了
print(d.new_name,d.new_age) # new_name的get方法执行了(因为d.new_name相当于调用了get方法),new_age的get方法执行了 田园犬 6
4.多重继承
4.1 简单继承
- 1.在Python中是支持多重继承的。也就是我们可以为一个类同时制定多个父类
- 2.可以在类名的()后边添加多个类,来实现多重继承
- 3.多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法
- 4.在开发中没有特殊情况,应该尽量避免使用多重继承。因为多重继承会让我们的代码更加复杂
- 5.如果多个父类中有同名的方法,则会先在第一个父类中寻找,然后找第二个,找第三个…前面会覆盖后面的
class A(object):
def test1(self):
print('A中test1的方法')
class B(object):
def test1(self):
print('B中test1的方法')
def test2(self):
print('B')
class C(B):
pass
c = C()
c.test1() # B中test1的方法
# print(C.__bases__) # (<class '__main__.B'>,)
class C(A,B):
pass
c = C()
c.test1() # A中test1的方法
# 在 python中是支持多继承的
# 类名.__bases__ 这个属性可以获取当前类的所有父类
# print(C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>)
4.2 钻石继承问题(遵循广度优先)
例1:不含super()
class A:
def func(self):
print('A')
class B(A):
pass
def func(self):
print('B')
class C(A):
pass
def func(self):
print('C')
class D(B):
pass
def func(self):
print('D')
class E(B,C):
pass
def func(self):
print('E')
class F(D,E):
pass
def func(self):
print('F')
f = F()
f.func() # F
print(F.mro()) # 广度优先的遍历顺序 简写为F->D->E->B->C->A
遍历顺序原则如下图示:
例2:含super(),此时需要采用子节点去寻找
class A:
def func(self):
print('A')
class B(A):
def func(self):
super().func()
print('B')
class C(A):
def func(self):
super().func()
print('C')
class D(B,C):
def func(self):
super().func()
print('D')
d = D()
d.func() # A C B D
print(D.mro()) # 遍历顺序简写为:D->B->C->A
**注:**这里的多继承是根据子节点去找的,执行d.func()的时候遇到super,去B中去找,B中也有Super,紧接着会去C,发现C也有super,由于广度优先,此时它会找到A,执行A,再返回C,执行C,再到B,再到D
遍历图示如下:
例3:简单介绍一下mro()的用法:
- 这个方法用于返回某个类的基类以及基类的基类,我们举一个简单的例子:创建一个类A,然后调用mro,它返回了一个列表,列表元素是类A本身和它的基类
class A:
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
class D(A):
def test(self):
print('from D')
class E(B):
def test(self):
print('from E')
class F(E,D,C):
def test(self):
print('from F')
print(F.mro()) # F->E->B->D->C->A
图示如下:
例4:含super()的计算实例
class Init(object):
def __init__(self,value):
self.val = value
class Add2(Init):
def __init__(self,val):
super(Add2,self).__init__(val)
self.val += 2
class Mul5(Init):
def __init__(self,val):
super(Mul5,self).__init__(val)
self.val *=5
class Pro(Mul5,Add2):
pass
class Incr(Pro):
csup = super(Pro)
def __init__(self,val):
self.csup.__init__(val)
self.val += 1
p = Incr(5)
print(p.val) # 36 (5+2)*5+1=36
图示:
思路: 从Incr开始,有super(),找到Pro,Pro中没有__init__属性,故先去找父类Mu15,发现有super(),故再去Add2(),发现也有super(),由于广度优先,则会去找到Init(),执行操作,再返回执行Add2(),再执行Mu15(),最后执行Incr
广度优先图:
5.多态
- 多态是面向对象的三大特性之一。从字面理解就是多种形态
- 一个对象可以由不同的形态去呈现(参考len()函数的用法,该函数可以处理不同类型的对象)
- 面向对象三大特性
• 封装 确保对象中数据的安全
• 基础 保证了对象的扩展性
• 多态 保证了程序的灵活性
# len()函数的用法
# len()函数之所以可以获取长度,是因为对象中有一个特殊方法 __len__
list = [1,2,3]
str = 'python'
print(len(list)) # 3
print(len(str)) # 6