官方文檔中關(guān)于super的定義說的不是很多,大致意思是返回一個代理對象讓你能夠調(diào)用一些繼承過來的方法,查找的機(jī)制遵循mro規(guī)則,最常用的情況如下面這個例子所示:
class C(B):
def method(self, arg):
super(C, self).method(arg)
子類C重寫了父類B中同名方法method,在重寫的實現(xiàn)中通過super實例化的代理對象調(diào)用父類的同名方法。
super類的初始方法簽名如下:
def __init__(self, type1, type2=None): # known special case of super.__init__
"""
super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type) -> unbound super object
super(type, type2) -> bound super object; requires issubclass(type2, type)
Typical use to call a cooperative superclass method:
除去self外接受一個或者或者兩個參數(shù),如同注釋聲明的一樣,接受兩個參數(shù)時返回的是綁定的super實例,省略第二個參數(shù)的時候返回的是未綁定的
super對象。
一般情況下當(dāng)調(diào)用繼承的類方法或者靜態(tài)方法時,并不需要綁定具體的實例,這個時候使用super(type, type2).some_method就能達(dá)到目的,當(dāng)然super(type, obj)在這種情況下也能夠使用,super對象有自定義實現(xiàn)的getattribute方法也能夠處理。不過,后者一般用來調(diào)用實例方法,這樣在查找方法的時候能夠傳入相應(yīng)的實例,從而得到綁定的實例方法:
class A(object):
def __init__(self):
pass
@classmethod
def klass_meth(cls):
pass
@staticmethod
def static_meth():
pass
def test(self):
pass
class B(A):
pass
>>> b = B()
>>> super(B, b).test
<bound method B.test of <__main__.B object at 0x02DA3570>>
>>> super(B, b).klass_meth
<bound method type.klass_meth of <class '__main__.B'>>
>>> super(B, b).static_meth
<function static_meth at 0x02D9CC70>
>>> super(B, B).test
<unbound method B.test>
>>> super(B, B).klass_meth
<bound method type.klass_meth of <class '__main__.B'>>
>>> super(B,B).satic_meth
>>> super(B,B).static_meth
<function static_meth at 0x02D9CC70>
初始化super對象的時候,傳遞的第二個參數(shù)其實是綁定的對象,第一個參感覺數(shù)可以粗暴地理解為標(biāo)記查找的起點(diǎn),比如上面例子中的情況:super(B, b).test就會在B.__mro__里面列出的除B本身的類中查找方法test,因為方法都是非數(shù)據(jù)描述符,在super對象的自定義getattribute里面實際上會轉(zhuǎn)化成A.__dict['test'].__get__(b, B)。
super在很多地方都會用到,除了讓程序不必hardcode指定類型讓代碼更加動態(tài),還有其他一些具體必用的地方比如元類中使用super查找baseclass里面的new生成自定義的類型模板;在自定義getattribute的時候用來防止無限循環(huán)等等。
關(guān)于super建議讀者將它與python的描述符一起來理解,因為super就實現(xiàn)了描述符的協(xié)議,是一個非數(shù)據(jù)描述符,能夠幫助大家更好的理解super的使用和工作原理。
參考資料: