91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在Python中使用super函數

發布時間:2020-12-31 16:25:48 來源:億速云 閱讀:117 作者:Leah 欄目:開發技術

如何在Python中使用super函數?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

help介紹如下:

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里面常用也是這種寫法.

另外, 在py2中, super只支持新類( new-style class, 就是繼承自object的).

為什么要調用父類?

在類繼承時, 要是重定義某個方法, 這個方法就會覆蓋掉父類的相應同名方法. 通過調用父類實例, 可以在子類中同時實現父類的功能.例如:

# Should be new-class based on object in python2.
class A(object):
 def __init__(self):
  print "enter A"
  print "leave A"
class B(A):
 def __init__(self):
  print "enter B"
  super(B, self).__init__()
  print "leave B"
>>> b = B()
enter B
enter A
leave A
leave B

通過調用super獲得父類實例從而可以實現該實例的初始化函數. 這在實踐中太常用了 (因為要繼承父類的功能, 又要有新的功能).

直接使用父類來調用的差異

事實上, 上面的super函數方法還可以這么寫:

class A(object):
 def __init__(self):
  print "enter A"
  print "leave A"
class B(A):
 def __init__(self):
  print "enter B"
  A.__init__(self)
  print "leave B"

通過直接使用父類類名來調用父類的方法, 實際也是可行的. 起碼在上面的例子中效果上他們現在是一樣的. 這種方法在老式類中也是唯一的調用父類的方法 (老式類沒有super).

通過父類類名調用方法很常用, 比較直觀. 但其效果和super還是有差異的. 例如:

class A(object):
 def __init__(self):
  print "enter A"
  print "leave A"
class B(A):
 def __init__(self):
  print "enter B"
  A.__init__(self)
  print "leave B"
class C(A):
 def __init__(self):
  print "enter C"
  A.__init__(self)
  print "leave C"
class D(B,C):
 def __init__(self):
  print "enter D"
  B.__init__(self)
  C.__init__(self)
  print "leave D"
>>> d=D()
enter D
enter B
enter A
leave A
leave B
enter C
enter A
leave A
leave C
leave D

可以發現, 這里面A的初始化函數被執行了兩次. 因為我們同時要實現B和C的初始化函數, 所以分開調用兩次, 這是必然的結果.

但如果改寫成super呢?

class A(object):
 def __init__(self):
  print "enter A"
  print "leave A"
class B(A):
 def __init__(self):
  print "enter B"
  super(B,self).__init__()
  print "leave B"
class C(A):
 def __init__(self):
  print "enter C"
  super(C,self).__init__()
  print "leave C"
class D(B,C):
 def __init__(self):
  print "enter D"
  super(D,self).__init__()
  print "leave D"
>>> d=D()
enter D
enter B
enter C
enter A
leave A
leave C
leave B
leave D

會發現所有父類ABC只執行了一次, 并不像之前那樣執行了兩次A的初始化.

然后, 又發現一個很奇怪的: 父類的執行是 BCA 的順序并且是全進入后再統一出去. 這是MRO表問題, 后面繼續討論.

如果沒有多繼承, super其實和通過父類來調用方法差不多. 但, super還有個好處: 當B繼承自A, 寫成了A.__init__, 如果根據需要進行重構全部要改成繼承自 E,那么全部都得改一次! 這樣很麻煩而且容易出錯! 而使用super()就不用一個一個改了(只需類定義中改一改就好了)

Anyway, 可以發現, super并不是那么簡單.

MRO 表

MRO是什么? 可以通過以下方式調出來:

>>> D.mro() # or d.__class__.mro() or D.__class__.mro(D) 
[D, B, C, A, object]
>>> B.mro()
[B, A, object]
>>> help(D.mro)
#Docstring:
#mro() -> list
#return a type's method resolution order
#Type:  method_descriptor

MRO就是類的方法解析順序表, 其實也就是繼承父類方法時的順序表 (類繼承順序表去理解也行) 啦.

這個表有啥用? 首先了解實際super做了啥:

def super(cls, inst):
 mro = inst.__class__.mro()
 return mro[mro.index(cls) + 1]

換而言之, super方法實際是調用了cls的在MRO表中的下一個類. 如果是簡單一條線的單繼承, 那就是父類->父類一個一個地下去羅. 但對于多繼承, 就要遵循MRO表中的順序了. 以上面的D的調用為例:

d的初始化

-> D (進入D) super(D,self)
-> 父類B (進入B) super(B,self)
-> 父類C (進入C) super(C,self)
-> 父父類A (進入A)  (退出A) # 如有繼續super(A,self)  -> object (停了)
-> (退出C)
-> (退出B)
-> (退出D)

所以, 在MRO表中的超類初始化函數只執行了一次!

那么, MRO的順序究竟是怎么定的呢? 這個可以參考官方說明The Python 2.3 Method Resolution Order . 基本就是, 計算出每個類(從父類到子類的順序)的MRO, 再merge 成一條線. 遵循以下規則:

在 MRO 中,基類永遠出現在派生類后面,如果有多個基類,基類的相對順序保持不變。 這個原則包括兩點:

1. 基類永遠在派生類后面
2. 類定義時的繼承順序影響相對順序.

如果有以下繼承 (Python中的super用法詳解):

    object
     /   \
    /      A
   |     /   \
  B-1  C-2   D-2
    \   /    /
     E-1    /
        \  /
          F

那么MRO是: F -> E -> B -> C -> D -> A -> object

怎么解釋呢?

根據官方的方法, 是:

L(O) = O
L(B) = B O
L(A) = A O
L(C) = C A O
L(D) = D A O
L(E) = E + merge(L(B),L(C))
  = E + merge(BO,CAO)
  = E + B + merge(O,CAO)
  = E + B + C + merge(O,AO)
  = E + B + C + A + merge(O,O)
  = E B C A O
L(F) = F + merge(L(E),L(D))
  = F + merge(EBCAO,DAO)
  = F + EBC + merge(AO,DAO)
  = F + EBC + D + merge(AO,AO)
  = F EBC D AO

看起來很復雜..但還是遵循在 MRO 中,基類永遠出現在派生類后面,如果有多個基類,基類的相對順序保持不變。所以, 我個人認為可以這么想:

  • 先找出最長深度最深的繼承路線F->E->C->A->object. (因為必然基類永遠出現在派生類后面)

  • 類似深度優先, 定出其余順序: F->E->B->obj, F->D->A-object

  • 如果有多個基類,基類的相對順序保持不變, 類似于merge時優先提前面的項. 所以排好這些路線: (FEBO, FECAO, FDAO)

  • F->E->B->obj且E(B,C)決定B在C前面.所以F->E->B->C->A->obj (相當于F+merge(EBO,ECAO)).

  • F->D->A-object且F(E,D)決定了D在E后, 所以D在E后A前. 因為相對順序, 相當于FE+merge(BCAO, DAO), 所以FE BC D AO

更多可參考

  • Raymond Hettinger 的Python's super() considered super! (據說很經典的討論)

  • James Knight 的 Python's Super Considered Harmful

  • Py3 cookbook: 8.7 調用父類方法http://python3-cookbook.readthedocs.org/zh_CN/latest/c08/p07_calling_method_on_parent_class.html

  • Python編程中對super函數的正確理解和用法解析

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

英吉沙县| 芦山县| 拜泉县| 屏东市| 奉化市| 华安县| 子洲县| 东源县| 金川县| 奉新县| 满洲里市| 滦平县| 洛浦县| 武宣县| 永丰县| 庄河市| 临夏市| 林芝县| 芦溪县| 山丹县| 嘉荫县| 陆川县| 祁连县| 溧阳市| 福鼎市| 沅江市| 宜宾县| 洛川县| 大关县| 都安| 香港| 桦川县| 乐亭县| 普洱| 青神县| 边坝县| 平江县| 南平市| 黄龙县| 恩平市| 临漳县|