一、单继承
- python中的继承,是可以继承父类所有方法,但是当我们在子类中写__ init__()方法的时候,相当于覆盖了父类的__init__()方法,若想要调用父类的__init__(),可以使用super().__ init__()
class A:
def __init__(self,a):
self.a = a
def spam(self):
print('A.spam')
class B(A):
def __init__(self,a,b):
self.b = b
super().__init__(a)
def spam(self):
print('B.spam')
super().spam()
b = B(1,2)
b.spam()
# 输出结果
# B.spam
# A.spam
二、多继承
- 在python中,处理多继承的方式非常复杂,其中有两个重要的概念,MRO数组,C3算法。
- C3算法是为了保证多继承中所有父类都只被实例化一次,因为python在实例化子类的时候首先会实例化父类,python解释器为用这个算法,把该类的所有父类的实例化顺序加入到一个MRO数组里。
- 而super()的使用就和这个密切相关。
class Person:
def __init__(self):
print('Person.__init__')
class Son1(Person):
def __init__(self):
super().__init__()
print('Son1.__init__')
class Son2(Person):
def __init__(self):
super().__init__()
print('Son2.__init__')
class GrandSon(Son1,Son2):
def __init__(self):
super().__init__() # Only one call to super() here
print('GrandSon.__init__')
g = GrandSon()
print(GrandSon.__mro__)
# 输出结果
# Person.__init__
# Son2.__init__
# Son1.__init__
# GrandSon.__init__
# (<class '__main__.GrandSon'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Person'>, <class 'object'>)
以上代码大概的继承方式就是这样
- 这里大家可以发现,若按照我们之前的理解是不是有点不太对,super()不是调用父类的方法么?
我们用GrandSon.__mro__输出了它所继承的类,super()的真实含义,其实就是在mro数组中,找super()所在的类,之后执行后面的类的方法。
创建GrandSon的对象的时候,我们调用了GrandSon的init()方法,第一句话就是super().init(),那就在mro数组里找GrandSon之后的类,也就是Son1,接着运行Son1的init方法,Son1的init方法第一句又是一个super(),那么就会在mro数组里找本类,也就是Son1类,找到Son1类,执行Son1类之后的Son2类的super()方法。
只不过单继承的mro数组里只有3个类罢了,本类,父类,Object,那么本类之后就是父类。
我们也可以指定到底调用谁之后的类,super(obj,self),这就检测的是obj之后的一个类,但是默认是本类之后的。
class A:
def sapm(self):
print('A.sapm')
super().sapm()
class B:
def sapm(self):
print('B.sapm')
class C(A,B):
pass
c = C()
c.sapm()
# 输出结果
# A.spam
# B.spam
分析一下这个代码,按照我们刚才的思想,次数的mro数组的内容应该是
C类,A类,B类
调用c对象的sapm()方法,但是C类中没有,就会自动去C之后的A对象去找,运行A类中的sapm()方法最后发现还有一个super,并且这个super是在A类中,就去找A类之后的B类,运行B类中的sapm()方法。
三、混入类
- 混入类本质上就是一个代码片段,是用来增强"兄弟"类中的同名函数,达到可拔插的效果。
- 例如我们要想一个自定义容器。
class LoggedMappingMixin():
def __getitem__(self,key):
print('获取{}'.format(key),end = ' ')
return super().__getitem__(key)
def __setitem__(self,key,value):
print('加入了键值对 {}:{}'.format(key,value))
super().__setitem__(key,value)
def __delitem__(self,key):
print('删除了{}'.format(key))
super().__delitem__(key)
class Dict(LoggedMappingMixin,dict):
pass
dict1 = Dict()
dict1['张三'] = '23'
print(dict1['张三'])
del dict1['张三']
# 输出结果
# 加入了键值对 张三:23
# 获取张三 23
# 删除了张三
这个就明显是强化之后的dict,在获取,添加,删除值的时候都有额外的打印。
由于在MRO中,dict在LoggedMappingMixin之后,所有LoggedMappingMixin调用super会直接调用dict里面的方法