0%

python:关于super

python2和python3中使用super的区别

super只能用在新式类中。在python3中的所有类都是新式类,而在python2继承object的才是新式类。

1
2
3
4
5
6
7
# python3 
class A:
pass

# python2
class A(object):
pass

python3可以直接使用super().xxx代替super(Class, self).xxx

1
2
3
4
5
6
7
8
9
# python3
class B(A):
def foo(self):
super().foo()

# python2
def B(A):
def foo(self):
super(B, self).foo()

单继承

在单继承中的super是主要用来调用父类的方法的。

1
2
3
4
5
6
7
8
class A:
def foo(self):
print('A.foo', self)

class B(A):
def foo(self):
super().foo()
print('B.foo', self)

执行以下代码

1
2
b = B()
b.foo()

执行结果如下

1
2
A.foo <__main__.B object at 0x000001548A54D828>
B.foo <__main__.B object at 0x000001548A54D828>

这个结果说明了两个问题:

  1. super().foo()调用了父类A的foo方法
  2. super().foo()调用父类方法时,父类方法中接收到的self对象不是父类实例而是子类的实例

多继承

再定义两个类,看看多继承会有什么不同

1
2
3
4
5
6
7
8
9
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四个类的继承关系是一个典型的“菱形继承”,如下:

1
2
3
4
5
6
7
   A
/ \
/ \
B C
\ /
\ /
D

执行以下代码

1
2
d = D()
d.foo()

输出如下

1
2
3
4
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类的实例。

1
2
3
4
5
6
7
>>> class A:
... pass
...
>>> s = super(A)
>>> type(s)
<class 'super'>
>>>

在大多数情况下,super对象包含了两个非常重要的信息,MRO(Method Resolution Order)列表和MRO中的一个类。

  1. 当使用super(type1, obj)方式调用super时,MRO列表指的是type(obj)的MRO列表,type1是MRO中的一个类,同时要满足isinstance(obj, type1) is True。
  2. 当使用super(type1, type2)方式调用super时,MRO指的是type2的MRO列表,type1是MRO中的一个类,同时issubclass(type2, type1) is True。

super会从MRO列表中type1之后的类中查找,查找要执行的方法对象后再返回这个对象。

比如说有个MRO列表:

1
[A, B, C, D, object]

下面的调用:

1
super(B, A).foo()

super只会从B之后查找,即只会在C、D、object中查找foo方法。

多继承中super的工作方式

回到前面的多继承的例子

1
2
d = D()
d.foo()

D的MRO是:[D, B, C, A, object]。(可以通过D.mro()来查看D的MRO信息)

代码分析如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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()