欧美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è)父類或者同輩的類去完成.

parent or sibling class 如何確定?

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

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

MRO中類的順序是怎么排的呢?

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

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

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

比如說:

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è)直接定義了該方法的類, 并實(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__方法的類, 于是就找到了Root, 然后調(diào)用Root.__init__(self), 這里的self是super()的第二個(gè)參數(shù), 是編譯器自動(dòng)填充的, 也就是A的__init__的第一個(gè)參數(shù), 這樣就完成對(duì)__init__方法調(diào)用的分配.

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

參數(shù)說明

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ù), 則找到的父類對(duì)象的self就綁定到這個(gè)參數(shù)上, 后面調(diào)用這個(gè)對(duì)象的方法時(shí), 可以自動(dòng)地隱式傳遞self.
如果第二個(gè)參數(shù)是一個(gè)對(duì)象, 則isinstance(obj, type)必須為True. 如果第二個(gè)參數(shù)為一個(gè)類型, 則issubclass(type2, type)必須為True

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

不帶參數(shù)的super()只能用在類定義中(因?yàn)橐蕾囉赾aller的第二個(gè)參數(shù)), 編譯器會(huì)自動(dòng)根據(jù)當(dāng)前定義的類填充參數(shù).
也就是說, 后面所有調(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()的兩種常見用法:

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

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

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

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

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

相關(guān)文章

最新評(píng)論