python2和python3中使用super的区别
super只能用在新式类中。在python3中的所有类都是新式类,而在python2继承object的才是新式类。
# python3
class A:
pass
# python2
class A(object):
pass
python3可以直接使用super().xxx代替super(Class, self).xxx
# python3
class B(A):
def foo(self):
super().foo()
# python2
def B(A):
def foo(self):
super(B, self).foo()
单继承
在单继承中的super是主要用来调用父类的方法的。
class A:
def foo(self):
print('A.foo', self)
class B(A):
def foo(self):
super().foo()
print('B.foo', self)
执行以下代码
b = B()
b.foo()
执行结果如下
A.foo <__main__.B object at 0x000001548A54D828>
B.foo <__main__.B object at 0x000001548A54D828>
这个结果说明了两个问题:
- super().foo()调用了父类A的foo方法
- super().foo()调用父类方法时,父类方法中接收到的self对象不是父类实例而是子类的实例
多继承
再定义两个类,看看多继承会有什么不同
class C(A):
def foo(self):
super().foo()
print('C.foo', self)
class D(B, C):
def foo(self):
super().foo()
print('D.foo', self)
ABCD四个类的继承关系是一个典型的“菱形继承”,如下:
A
/ \
/ \
B C
\ /
\ /
D
执行以下代码
d = D()
d.foo()
输出如下
A.foo <__main__.D object at 0x000001DDD2AADB70>
C.foo <__main__.D object at 0x000001DDD2AADB70>
B.foo <__main__.D object at 0x000001DDD2AADB70>
D.foo <__main__.D object at 0x000001DDD2AADB70>
从结果可以看出,C并不是B的父类,但是B类中的super().foo()却调用了C类的foo方法,这是为什么呢?
在多继承中使用super并不像单继承那么简单,会涉及到方法查找顺序(MRO)。
super如何查找方法
super实质上是一个类,而不是函数或者其他数据结构。
当调用super()的时候,实际上是创建了一个super类的实例。
>>> class A:
... pass
...
>>> s = super(A)
>>> type(s)
<class 'super'>
>>>
在大多数情况下,super对象包含了两个非常重要的信息,MRO(Method Resolution Order)列表和MRO中的一个类。
- 当使用super(type1, obj)方式调用super时,MRO列表指的是type(obj)的MRO列表,type1是MRO中的一个类,同时要满足isinstance(obj, type1) is True。
- 当使用super(type1, type2)方式调用super时,MRO指的是type2的MRO列表,type1是MRO中的一个类,同时issubclass(type2, type1) is True。
super会从MRO列表中type1之后的类中查找,查找要执行的方法对象后再返回这个对象。
比如说有个MRO列表:
[A, B, C, D, object]
下面的调用:
super(B, A).foo()
super只会从B之后查找,即只会在C、D、object中查找foo方法。
多继承中super的工作方式
回到前面的多继承的例子
d = D()
d.foo()
D的MRO是:[D, B, C, A, object]。(可以通过D.mro()来查看D的MRO信息)
代码分析如下:
class A:
def foo(self):
# 第四步
print('A.foo', self)
class B(A):
def foo(self):
# 第二步
# 等价于super(B, self).foo()
# self的MRO是[D, B, C, A, object]
# 从B之后的[C, A, object]中查找foo方法
super().foo()
# 第六步
print('B.foo', self)
class C(A):
def foo(self):
# 第三步
# 等价于super(C, self).foo()
# self的MRO是[D, B, C, A, object]
# 从C之后的[A, object]中查找foo方法
super().foo()
# 第五步
print('C.foo', self)
class D(B, C):
def foo(self):
# 第一步
# 等价于super(D, self).foo()
# self的MRO是[D, B, C, A, object]
# 从D之后的[B, C, A, object]中查找foo方法
super().foo()
# 第七步
print('D.foo', self)
d = D()
d.foo()
关于super的内容就这么多。在多继承模式中mro的计算方式会在另一篇文章中讲述。