小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

super 沒那么簡單

 萬皇之皇 2018-02-17




說到 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è)問題:


  1. super().add(m) 確實(shí)調(diào)用了父類 A 的 add 方法。

  2. 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() Explained

  • 2. Built-in Functions — Python 3.5.2 documentation

  • Python’s Super Considered Harmful



來源:HuangHuang

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多