欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python中super()函數(shù)簡(jiǎn)介及用法分享

 更新時(shí)間:2016年07月11日 08:49:48   投稿:hebedich  
本文給大家分享的是Python中的super函數(shù)的簡(jiǎn)單介紹以及用法和注意事項(xiàng),有需要的小伙伴可以參考下

首先看一下super()函數(shù)的定義:

super([type [,object-or-type]])

Return a **proxy object** that delegates method calls to a **parent or sibling** class of type.

返回一個(gè)代理對(duì)象, 這個(gè)對(duì)象負(fù)責(zé)將方法調(diào)用分配給第一個(gè)參數(shù)的一個(gè)父類(lèi)或者同輩的類(lèi)去完成.

parent or sibling class 如何確定?

第一個(gè)參數(shù)的__mro__屬性決定了搜索的順序, super指的的是 MRO(Method Resolution Order) 中的下一個(gè)類(lèi), 而不一定是父類(lèi)!

super()和getattr() 都使用__mro__屬性來(lái)解析搜索順序, __mro__實(shí)際上是一個(gè)只讀的元組.

MRO中類(lèi)的順序是怎么排的呢?

實(shí)際上MRO列表本身是根據(jù)一種C3的線性化處理技術(shù)確定的, 理論說(shuō)明可以參考這里, 這里只簡(jiǎn)單說(shuō)明一下原則:

在MRO中, 基類(lèi)永遠(yuǎn)出現(xiàn)在派生類(lèi)的后面, 如果有多個(gè)基類(lèi), 基類(lèi)的相對(duì)順序不變.

MRO實(shí)際上是對(duì)繼承樹(shù)做層序遍歷的結(jié)果, 把一棵帶有結(jié)構(gòu)的樹(shù)變成了一個(gè)線性的表, 所以沿著這個(gè)列表一直往上, 就可以無(wú)重復(fù)的遍歷完整棵樹(shù), 也就解決了多繼承中的Diamond問(wèn)題.

比如說(shuō):

class Root:
  pass

class A(Root):
  pass

class B(Root):
  pass

class C(A, B):
  pass

print(C.__mro__)

# 輸出結(jié)果為:
# (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Root'>, <class 'object'>)

super()實(shí)際返回的是一個(gè)代理的super對(duì)象!

調(diào)用super()這個(gè)構(gòu)造方法時(shí), 只是返回一個(gè)super()對(duì)象, 并不做其他的操作.

然后對(duì)這個(gè)super對(duì)象進(jìn)行方法調(diào)用時(shí), 發(fā)生的事情如下:

找到第一個(gè)參數(shù)的__mro__列表中的下一個(gè)直接定義了該方法的類(lèi), 并實(shí)例化出一個(gè)對(duì)象
然后將這個(gè)對(duì)象的self變量綁定到第二個(gè)參數(shù)上, 返回這個(gè)對(duì)象

舉個(gè)例子:

class Root:
  def __init__(self):
    print('Root')

class A(Root):
  def __init__(self):
    super().__init__() # 等同于super(A, self).__init__()

在A的構(gòu)造方法中, 先調(diào)用super()得到一個(gè)super對(duì)象, 然后向這個(gè)對(duì)象調(diào)用init方法, 這是super對(duì)象會(huì)搜索A的__mro__列表, 找到第一個(gè)定義了__init__方法的類(lèi), 于是就找到了Root, 然后調(diào)用Root.__init__(self), 這里的self是super()的第二個(gè)參數(shù), 是編譯器自動(dòng)填充的, 也就是A的__init__的第一個(gè)參數(shù), 這樣就完成對(duì)__init__方法調(diào)用的分配.

注意: 在許多語(yǔ)言的繼承中, 子類(lèi)必須調(diào)用父類(lèi)的構(gòu)造方法, 就是為了保證子類(lèi)的對(duì)象能夠填充上父類(lèi)的屬性! 而不是初始化一個(gè)父類(lèi)對(duì)象...(我之前就一直是這么理解的..). Python中就好多了, 所謂的調(diào)用父類(lèi)構(gòu)造方法, 就是明明白白地把self傳給父類(lèi)的構(gòu)造方法, 我的小身子骨就這么交給你了, 隨便你怎么折騰吧:joy:

參數(shù)說(shuō)明

super() -> same as super(__class__, <first argument>) # <first argument>指的是調(diào)用super的函數(shù)的第一個(gè)參數(shù)
super(type) -> unbound super object
super(type, obj) -> bound super object; requires isinstance(obj, type)
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().meth(arg)
  This works for class methods too:
  class C(B):
    @classmethod
    def cmeth(cls, arg):
      super().cmeth(arg)

如果提供了第二個(gè)參數(shù), 則找到的父類(lèi)對(duì)象的self就綁定到這個(gè)參數(shù)上, 后面調(diào)用這個(gè)對(duì)象的方法時(shí), 可以自動(dòng)地隱式傳遞self.
如果第二個(gè)參數(shù)是一個(gè)對(duì)象, 則isinstance(obj, type)必須為T(mén)rue. 如果第二個(gè)參數(shù)為一個(gè)類(lèi)型, 則issubclass(type2, type)必須為T(mén)rue

如果沒(méi)有傳遞第二個(gè)參數(shù), 那么返回的對(duì)象就是Unbound, 調(diào)用這個(gè)unbound對(duì)象的方法時(shí)需要手動(dòng)傳遞第一個(gè)參數(shù), 類(lèi)似于Base.__int__(self, a, b).

不帶參數(shù)的super()只能用在類(lèi)定義中(因?yàn)橐蕾?lài)于caller的第二個(gè)參數(shù)), 編譯器會(huì)自動(dòng)根據(jù)當(dāng)前定義的類(lèi)填充參數(shù).
也就是說(shuō), 后面所有調(diào)用super返回對(duì)象的方法時(shí), 第一個(gè)參數(shù)self都是super()的第二個(gè)參數(shù). 因?yàn)镻ython中所謂的方法, 就是一個(gè)第一個(gè)參數(shù)為self的函數(shù), 一般在調(diào)用方法的時(shí)候a.b()會(huì)隱式的將a賦給b()的第一個(gè)參數(shù).

super()的兩種常見(jiàn)用法:

單繼承中, super用來(lái)指代隱式指代父類(lèi), 避免直接使用父類(lèi)的名字
多繼承中, 解決Diamond問(wèn)題 (TODO)

對(duì)面向?qū)ο蟮睦斫?/p>

其實(shí)我覺(jué)得Python里面這樣的語(yǔ)法更容易理解面向?qū)ο蟮谋举|(zhì), 比Java中隱式地傳this更容易理解.

所謂函數(shù), 就是一段代碼, 接受輸入, 返回輸出. 所謂方法, 就是一個(gè)函數(shù)有了一個(gè)隱式傳遞的參數(shù). 所以方法就是一段代碼, 是類(lèi)的所有實(shí)例共享的, 唯一不同的是各個(gè)實(shí)例調(diào)用的時(shí)候傳給方法的this 或者self不一樣而已.

構(gòu)造方法是什么呢? 其實(shí)也是一個(gè)實(shí)例方法啊, 它只有在對(duì)象生成了之后才能調(diào)用, 所以Python中__init__方法的參數(shù)是self啊. 調(diào)用構(gòu)造方法時(shí)其實(shí)已經(jīng)為對(duì)象分配了內(nèi)存, 構(gòu)造方法只是起到初始化的作用, 也就是為這段內(nèi)存里面賦點(diǎn)初值而已.

Java中所謂的靜態(tài)變量其實(shí)也就是類(lèi)的變量, 其實(shí)也就是為類(lèi)也分配了內(nèi)存, 里面存了這些變量, 所以Python中的類(lèi)對(duì)象我覺(jué)得是很合理的, 也比Java要直觀. 至于靜態(tài)方法, 那就與對(duì)象一點(diǎn)關(guān)系都沒(méi)有了, 本質(zhì)就是個(gè)獨(dú)立的函數(shù), 只不過(guò)寫(xiě)在了類(lèi)里面而已. 而Python中的classmethod其實(shí)也是一種靜態(tài)方法, 不過(guò)它會(huì)依賴(lài)于cls對(duì)象, 這個(gè)cls就是類(lèi)對(duì)象, 但是只要想用這個(gè)方法, 類(lèi)對(duì)象必然是存在的, 不像實(shí)例對(duì)象一樣需要手動(dòng)的實(shí)例化, 所以classmethod也可以看做是一種靜態(tài)變量. 而staticmethod就是真正的靜態(tài)方法了, 是獨(dú)立的函數(shù), 不依賴(lài)任何對(duì)象.

Java中的實(shí)例方法是必須依賴(lài)于對(duì)象存在的, 因?yàn)橐[式的傳輸this, 如果對(duì)象不存在這個(gè)this也沒(méi)法隱式了. 所以在靜態(tài)方法中是沒(méi)有this指針的, 也就沒(méi)法調(diào)用實(shí)例方法. 而Python中的實(shí)例方法是可以通過(guò)類(lèi)名來(lái)調(diào)用的, 只不過(guò)因?yàn)檫@時(shí)候self沒(méi)辦法隱式傳遞, 所以必須得顯式地傳遞.

相關(guān)文章

最新評(píng)論