寫這篇文章來自於兩個疑問:python
1. super如何用?bash
2. 既然子類裏有繼承的父類,爲何不是父類.函數方式調用,而是super方式調用?函數
super是python內置類oop
用法以下ui
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: class C(B): def meth(self, arg): super(C, self).meth(arg)
由此可知, super有三種用法, 第一參數老是調用父類的那個類, 第二參數可缺(返回非綁定父類對象),也能夠是實例對象或該類的子類. 最終返回的都是父類的實例(綁定或非綁定). 在Python3中,super函數多了一種用法是直接super()
,至關於super(type,首參)
, 這個首參就是通常的傳入的self
實例自己啦. 由於在py2裏面經常使用也是這種寫法.spa
另外, 在py2中, super只支持新類( new-style class, 就是繼承自object的).code
class Base(object): def __init__(self): print("Base created") class ChildA(Base): def __init__(self): Base.__init__(self) class ChildB(Base): def __init__(self): super(ChildB, self).__init__() ChildA() ChildB()
如上兩種方式均可正確調用父類方法,但有什麼區別?對象
目前來看是同樣的,可是若是遇到多重繼承該怎麼辦,不以下面繼承
class ChildC(ChildA, ChildB): def __init__(self): ...
假如ChildA和ChildB裏都有ChildC須要繼承的屬性,方法等,那麼類名.函數名(self)的方式就得調用兩次,這是缺點1,缺點2就是它還會重複調用it
class Base(object): def __init__(self): print("Base created") class ChildA(Base): def __init__(self): # Base.__init__(self) print("ChildA created") super(ChildA, self).__init__() class ChildB(Base): def __init__(self): print("ChildB created") super(ChildB, self).__init__() class ChildC(ChildA, ChildB): def __init__(self): print("ChildC created") ChildA.__init__(self) ChildB.__init__(self) c = ChildC() # 輸出 ChildC created ChildA created ChildB created Base created ChildB created Base created
可見ChildB Base重複調用了
若是換作super的話就可去除這2個缺點
class Base(object): def __init__(self): print("Base created") class ChildA(Base): def __init__(self): # Base.__init__(self) print("ChildA created") super(ChildA, self).__init__() class ChildB(Base): def __init__(self): print("ChildB created") super(ChildB, self).__init__() class ChildC(ChildA, ChildB): def __init__(self): print("ChildC created") super(ChildC, self).__init__() c = ChildC() print(c.__class__.__mro__) # 輸出 ChildC created ChildA created ChildB created Base created [<class '__main__.ChildC'>, <class '__main__.ChildA'>, <class '__main__.ChildB'>, <class '__main__.Base'>, <type 'object'>]
可見代碼整潔了,並且重複調用沒了,並且可避免直接使用父類名
super其實幹的是這件事:
def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1]
兩個參數 cls 和 inst 分別作了兩件事:
1. inst 負責生成 MRO 的 list
2. 經過 cls 定位當前 MRO 中的 index, 並返回 mro[index + 1]
這兩件事纔是 super 的實質,必定要記住!
MRO 全稱 Method Resolution Order,它表明了類繼承的順序。
注意super調用父類的方法時,父類裏的self都是指的當前子類的實例
class Base(object): n = 5 def __init__(self, n): print("Base created") self.n += n class ChildA(Base): n = 10 def __init__(self, n): print("ChildA created") super(ChildA, self).__init__(n) self.n += n c = ChildA(2) print(c.n) print(c.__class__.__mro__) # 輸出 ChildA created Base created 14 (<class '__main__.ChildA'>, <class '__main__.Base'>, <type 'object'>)
上面父類調用父類__init__(self, n)方法時,self是子類ChildA的實例c,底層c開始調用,c實例一直往上傳遞