日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python中的super用法详解_Python中super函数用法实例分析

發(fā)布時間:2023/12/3 python 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python中的super用法详解_Python中super函数用法实例分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文實(shí)例講述了python中super函數(shù)用法。分享給大家供大家參考,具體如下:

這是個高大上的函數(shù),在python裝13手冊里面介紹過多使用可顯得自己是高手 23333. 但其實(shí)他還是很重要的. 簡單說, super函數(shù)是調(diào)用下一個父類(超類)并返回該父類實(shí)例的方法. 這里的下一個的概念參考后面的MRO表介紹.

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有三種用法, 第一參數(shù)總是召喚父類的那個類, 第二參數(shù)可缺(返回非綁定父類對象),也可以是實(shí)例對象或該類的子類. 最終返回的都是父類的實(shí)例(綁定或非綁定). 在Python3中,super函數(shù)多了一種用法是直接super(),相當(dāng)于super(type,首參), 這個首參就是一般的傳入的self實(shí)例本身啦. 因?yàn)樵趐y2里面常用也是這種寫法.

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

為什么要調(diào)用父類?

在類繼承時, 要是重定義某個方法, 這個方法就會覆蓋掉父類的相應(yīng)同名方法. 通過調(diào)用父類實(shí)例, 可以在子類中同時實(shí)現(xiàn)父類的功能.例如: # 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

通過調(diào)用super獲得父類實(shí)例從而可以實(shí)現(xiàn)該實(shí)例的初始化函數(shù). 這在實(shí)踐中太常用了 (因?yàn)橐^承父類的功能, 又要有新的功能).

直接使用父類來調(diào)用的差異

事實(shí)上, 上面的super函數(shù)方法還可以這么寫: 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"

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

通過父類類名調(diào)用方法很常用, 比較直觀. 但其效果和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

可以發(fā)現(xiàn), 這里面A的初始化函數(shù)被執(zhí)行了兩次. 因?yàn)槲覀兺瑫r要實(shí)現(xiàn)B和C的初始化函數(shù), 所以分開調(diào)用兩次, 這是必然的結(jié)果.

但如果改寫成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

會發(fā)現(xiàn)所有父類ABC只執(zhí)行了一次, 并不像之前那樣執(zhí)行了兩次A的初始化.

然后, 又發(fā)現(xiàn)一個很奇怪的: 父類的執(zhí)行是 BCA 的順序并且是全進(jìn)入后再統(tǒng)一出去. 這是MRO表問題, 后面繼續(xù)討論.

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

Anyway, 可以發(fā)現(xiàn), super并不是那么簡單.

MRO 表

MRO是什么? 可以通過以下方式調(diào)出來: >>> 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就是類的方法解析順序表, 其實(shí)也就是繼承父類方法時的順序表 (類繼承順序表去理解也行) 啦.

這個表有啥用? 首先了解實(shí)際super做了啥: def super(cls, inst):

mro = inst.__class__.mro()

return mro[mro.index(cls) + 1]

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

d的初始化

-> D (進(jìn)入D) super(D,self)

-> 父類B (進(jìn)入B) super(B,self)

-> 父類C (進(jìn)入C) super(C,self)

-> 父父類A (進(jìn)入A) (退出A) # 如有繼續(xù)super(A,self) -> object (停了)

-> (退出C)

-> (退出B)

-> (退出D)

所以, 在MRO表中的超類初始化函數(shù)只執(zhí)行了一次!

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

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

1. 基類永遠(yuǎn)在派生類后面

2. 類定義時的繼承順序影響相對順序.

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

object

/ \

/ A

| / \

B-1 C-2 D-2

\ / /

E-1 /

\ /

F

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

怎么解釋呢?

根據(jù)官方的方法, 是: 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

看起來很復(fù)雜..但還是遵循在 MRO 中,基類永遠(yuǎn)出現(xiàn)在派生類后面,如果有多個基類,基類的相對順序保持不變。所以, 我個人認(rèn)為可以這么想: 先找出最長深度最深的繼承路線F->E->C->A->object. (因?yàn)楸厝换愑肋h(yuǎn)出現(xiàn)在派生類后面) 類似深度優(yōu)先, 定出其余順序: F->E->B->obj, F->D->A-object 如果有多個基類,基類的相對順序保持不變, 類似于merge時優(yōu)先提前面的項(xiàng). 所以排好這些路線: (FEBO, FECAO, FDAO) F->E->B->obj且E(B,C)決定B在C前面.所以F->E->B->C->A->obj(相當(dāng)于F+merge(EBO,ECAO)). F->D->A-object且F(E,D)決定了D在E后, 所以D在E后A前. 因?yàn)橄鄬樞? 相當(dāng)于FE+merge(BCAO, DAO), 所以FE BC D AO

更多可參考 Raymond Hettinger 的Python's super() considered super! (據(jù)說很經(jīng)典的討論) James Knight 的 Python's Super Considered Harmful Py3 cookbook: 8.7 調(diào)用父類方法http://python3-cookbook.readthedocs.org/zh_CN/latest/c08/p07_calling_method_on_parent_class.html Python編程中對super函數(shù)的正確理解和用法解析

關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python面向?qū)ο蟪绦蛟O(shè)計(jì)入門與進(jìn)階教程》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python編碼操作技巧總結(jié)》及《Python入門與進(jìn)階經(jīng)典教程》

希望本文所述對大家Python程序設(shè)計(jì)有所幫助。

總結(jié)

以上是生活随笔為你收集整理的python中的super用法详解_Python中super函数用法实例分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。