| 
 
 
 說到 super, 大家可能覺得很簡單呀,不就是用來調(diào)用父類方法的嘛。如果真的這么簡單的話也就不會(huì)有這篇文章了,且聽我細(xì)細(xì)道來。?? 
 約定 
 在開始之前我們來約定一下本文所使用的 Python 版本。默認(rèn)用的是 Python 3,也就是說:本文所定義的類都是新式類。如果你用到是 Python 2 的話,記得繼承 object: 
 # 默認(rèn), Python 3 class A:     pass   # Python 2 class A(object):     pass
 
 Python 3 和 Python 2 的另一個(gè)區(qū)別是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx : 
 # 默認(rèn),Python 3 class B(A):     def add(self, x):         super().add(x)   # Python 2 class B(A):     def add(self, x):         super(B, self).add(x)
 
 所以,你如果用的是 Python 2 的話,記得將本文的 super() 替換為 suepr(Class, self) 。 
 如果還有其他不兼容 Python 2 的情況,我會(huì)在文中注明的。 
 單繼承 
 在單繼承中 super 就像大家所想的那樣,主要是用來調(diào)用父類的方法的。 
 class A:     def __init__(self):         self.n = 2       def add(self, m):         print('self is {0} @A.add'.format(self))         self.n += m     class B(A):     def __init__(self):         self.n = 3       def add(self, m):         print('self is {0} @B.add'.format(self))         super().add(m)         self.n += 3
 
 你覺得執(zhí)行下面代碼后, b.n 的值是多少呢? 
 b = B() b.add(2) print(b.n)
 
 執(zhí)行結(jié)果如下: 
 self is __main__.B object at 0x106c49b38> @B.add self is __main__.B object at 0x106c49b38> @A.add 8
 
 這個(gè)結(jié)果說明了兩個(gè)問題: 
 super().add(m) 確實(shí)調(diào)用了父類 A 的 add 方法。super().add(m) 調(diào)用父類方法 def add(self, m) 時(shí), 此時(shí)父類中 self 并不是父類的實(shí)例而是子類的實(shí)例, 所以 b.add(2) 之后的結(jié)果是 5 而不是 4 。
 
 不知道這個(gè)結(jié)果是否和你想到一樣呢?下面我們來看一個(gè)多繼承的例子。 
 多繼承 
 這次我們再定義一個(gè) class C,一個(gè) class D: 
 class C(A):     def __init__(self):         self.n = 4       def add(self, m):         print('self is {0} @C.add'.format(self))         super().add(m)         self.n += 4     class D(B, C):     def __init__(self):         self.n = 5       def add(self, m):         print('self is {0} @D.add'.format(self))         super().add(m)         self.n += 5
 
 下面的代碼又輸出啥呢? 
 d = D() d.add(2) print(d.n)
 
 這次的輸出如下: 
 self is __main__.D object at 0x10ce10e48> @D.add self is __main__.D object at 0x10ce10e48> @B.add self is __main__.D object at 0x10ce10e48> @C.add self is __main__.D object at 0x10ce10e48> @A.add 19
 
 你說對(duì)了嗎?你可能會(huì)認(rèn)為上面代碼的輸出類似: 
 self is __main__.D object at 0x10ce10e48> @D.add self is __main__.D object at 0x10ce10e48> @B.add self is __main__.D object at 0x10ce10e48> @A.add 15
 
 為什么會(huì)跟預(yù)期的不一樣呢?下面我們將一起來看看 super 的奧秘。 
 super 是個(gè)類 
 當(dāng)我們調(diào)用 super() 的時(shí)候,實(shí)際上是實(shí)例化了一個(gè) super 類。你沒看錯(cuò), super 是個(gè)類,既不是關(guān)鍵字也不是函數(shù)等其他數(shù)據(jù)結(jié)構(gòu): 
 >>> class A: pass ... >>> s = super(A) >>> type(s) class 'super'> >>>
 
 在大多數(shù)情況下, super 包含了兩個(gè)非常重要的信息: 一個(gè) MRO 以及 MRO 中的一個(gè)類。當(dāng)以如下方式調(diào)用 super 時(shí): : 
 super(a_type, obj)
 
 
 MRO 指的是 type(obj) 的 MRO, MRO 中的那個(gè)類就是 a_type , 同時(shí) isinstance(obj, a_type) == True 。 
 當(dāng)這樣調(diào)用時(shí): : 
 super(type1, type2)
 
 
 MRO 指的是 type2 的 MRO, MRO 中的那個(gè)類就是 type1 ,同時(shí) issubclass(type2, type1) == True 。 
 那么, super() 實(shí)際上做了啥呢?簡單來說就是:提供一個(gè) MRO 以及一個(gè) MRO 中的類 C , super() 將返回一個(gè)從 MRO 中 C 之后的類中查找方法的對(duì)象。 
 也就是說,查找方式時(shí)不是像常規(guī)方法一樣從所有的 MRO 類中查找,而是從 MRO 的 tail 中查找。 
 舉個(gè)栗子, 有個(gè) MRO: : 
 [A, B, C, D, E, object] 
 
 super 只會(huì)從 C 之后查找,即: 只會(huì)在 D 或 E 或 object 中查找 foo 方法。 
 多繼承中 super 的工作方式 
 再回到前面的 
 d = D() d.add(2) print(d.n)
 
 現(xiàn)在你可能已經(jīng)有點(diǎn)眉目,為什么輸出會(huì)是 : 
 self is __main__.D object at 0x10ce10e48> @D.add self is __main__.D object at 0x10ce10e48> @B.add self is __main__.D object at 0x10ce10e48> @C.add self is __main__.D object at 0x10ce10e48> @A.add 19
 
 了吧 ;) 
 下面我們來具體分析一下: 
 D 的 MRO 是: [D, B, C, A, object] 。 備注: 可以通過 D.mro() (Python 2 使用 D.__mro__ ) 來查看 D 的 MRO 信息)詳細(xì)的代碼分析如下:
 
 class A:     def __init__(self):         self.n = 2       def add(self, m):         # 第四步         # 來自 D.add 中的 super         # self == d, self.n == d.n == 5         print('self is {0} @A.add'.format(self))         self.n += m         # d.n == 7     class B(A):     def __init__(self):         self.n = 3       def add(self, m):         # 第二步         # 來自 D.add 中的 super         # self == d, self.n == d.n == 5         print('self is {0} @B.add'.format(self))         # 等價(jià)于 suepr(B, self).add(m)         # self 的 MRO 是 [D, B, C, A, object]         # 從 B 之后的 [C, A, object] 中查找 add 方法         super().add(m)           # 第六步         # d.n = 11         self.n += 3         # d.n = 14   class C(A):     def __init__(self):         self.n = 4       def add(self, m):         # 第三步         # 來自 B.add 中的 super         # self == d, self.n == d.n == 5         print('self is {0} @C.add'.format(self))         # 等價(jià)于 suepr(C, self).add(m)         # self 的 MRO 是 [D, B, C, A, object]         # 從 C 之后的 [A, object] 中查找 add 方法         super().add(m)           # 第五步         # d.n = 7         self.n += 4         # d.n = 11     class D(B, C):     def __init__(self):         self.n = 5       def add(self, m):         # 第一步         print('self is {0} @D.add'.format(self))         # 等價(jià)于 super(D, self).add(m)         # self 的 MRO 是 [D, B, C, A, object]         # 從 D 之后的 [B, C, A, object] 中查找 add 方法         super().add(m)           # 第七步         # d.n = 14         self.n += 5         # self.n = 19   d = D() d.add(2) print(d.n)
 
 調(diào)用過程圖如下: 
 D.mro() == [D, B, C, A, object] d = D() d.n == 5 d.add(2)   class D(B, C):          class B(A):            class C(A):             class A:     def add(self, m):       def add(self, m):      def add(self, m):       def add(self, m):         super().add(m)  1.--->  super().add(m) 2.--->  super().add(m)  3.--->  self.n += m         self.n += 5   <>6. self.n += 3    <>5. self.n += 4     <>4. <>         (14+5=19)               (11+3=14)              (7+4=11)                (5+2=7)
 
 現(xiàn)在你知道為什么 d.add(2) 后 d.n 的值是 19 了吧 ;) 
 That’s all! 希望這篇文章能對(duì)你有所幫助 ;) 
 參考資料 
 Python’s super() Explained2. Built-in Functions — Python 3.5.2 documentationPython’s Super Considered Harmful
 
 
 
 來源:HuangHuang
 |