子類里訪問父類的同名屬性,而又不想直接引用父類的名字,因?yàn)檎f不定什么時候會去修改它,所以數(shù)據(jù)還是只保留一份的好。其實(shí)呢,還有更好的理由不去直接引用父類的名字,參見 Python's super() considered super! | Deep Thoughts by Raymond Hettinger。
這時候就該 super() 登場啦——
class A:
def m(self):
print('A')
class B(A):
def m(self):
print('B')
super().m()
B().m()
當(dāng)然 Python 2 里 super() 是一定要參數(shù)的,所以得這么寫:
class B(A):
def m(self):
print('B')
super(B, self).m()
需要提到自己的名字。這個名字也是動態(tài)查找的,在這種情況下替換第三方庫中的類會出問題。
super() 很好地解決了訪問父類中的方法的問題。那么,如果要訪問父類的父類(準(zhǔn)確地說,是方法解析順序(MRO)中位于第三的類)的屬性呢?
比如,B 類是繼承 A 的,它重寫了 A 的 m 方法。現(xiàn)在我們需要一個 C 類,它需要 B 類的一些方法,但是不要 B 的 m 方法,而改用 A 的。怎么間接地引用到 A 的 m 方法呢?使用self.__class__肯定是不行的,因?yàn)?C 還可能被進(jìn)一步繼承。
從文檔中我注意到,super 的實(shí)現(xiàn)是通過插入一個名為 __class__ 的名字來實(shí)現(xiàn)的(super 會從調(diào)用棧里去查找這個 __class__ 名字)。所以,就像文檔里暗示的,其實(shí)可以直接在定義方法時訪問 __class__ 名字,它總是該方法被定義的類。繼續(xù)我們的單字母類:
class C(B):
def m(self):
print('C')
# see the difference!
print(__class__.__mro__)
print(self.__class__.__mro__)
__class__.__mro__[2].m(self)
class D(C):
def m(self):
print('D')
super().m()
o = D()
o.m()
會得到:
D
C
(<class 't.C'>, <class 't.B'>, <class 't.A'>, <class 'object'>)
(<class 't.D'>, <class 't.C'>, <class 't.B'>, <class 't.A'>, <class 'object'>)
A
不過,PyPy 并不支持這個 __class__ 名字。