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的計算方式會在另一篇文章中講述。