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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

深入super,看Python如何解决钻石继承难题

發布時間:2025/4/9 python 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入super,看Python如何解决钻石继承难题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.?? Python的繼承以及調用父類成員

python子類調用父類成員有2種方法,分別是普通方法和super方法

假設Base是基類

class Base(object):def __init__(self):print “Base init”

則普通方法如下

class Leaf(Base):def __init__(self):Base.__init__(self)print “Leaf init”

super方法如下

class Leaf(Base):def __init__(self):super(Leaf, self).__init__()print “Leaf init”

在上面的簡單場景下,兩種方法的效果一致:

>>> leaf = Leaf()

Base init

Leaf init

2.?? 鉆石繼承遇到的難題

當我們來到鉆石繼承場景時,我們就遇到了一個難題:

如果我們還是使用普通方法調用父類成員,代碼如下:

class Base(object):def __init__(self):print “Base init”class Medium1(Base):def __init__(self):Base.__init__(self)print “Medium1 init”class Medium2(Base):def __init__(self):Base.__init__(self)print “Medium2 init”class Leaf(Medium1, Medium2):def __init__(self):Medium1.__init__(self)Medium2.__init__(self)print “Leaf init”

當我們生成Leaf對象時,結果如下:

>>> leaf = Leaf()

Base init

Medium1 init

Base init

Medium2 init

Leaf init

?

可以看到Base被初始化了兩次!這是由于Medium1和Medium2各自調用了Base的初始化函數導致的。

3.?? 各語言的解決方法

鉆石繼承中,父類被多次初始化是個非常難纏的問題,我們來看看其他各個語言是如何解決這個問題的:

3.1. C++

C++使用虛擬繼承來解決鉆石繼承問題。

Medium1和Medium2虛擬繼承Base。當生成Leaf對象時,Medium1和Medium2并不會自動調用虛擬基類Base的構造函數,而需要由Leaf的構造函數顯式調用Base的構造函數。

3.2. Java

Java禁止使用多繼承。

Java使用單繼承+接口實現的方式來替代多繼承,避免了鉆石繼承產生的各種問題。

3.3. Ruby

Ruby禁止使用多繼承。

Ruby和Java一樣只支持單繼承,但它對多繼承的替代方式和Java不同。Ruby使用Mixin的方式來替代,在當前類中mixin入其他模塊,來做到代碼的組裝效果。

3.4. Python

Python和C++一樣,支持多繼承的語法。但Python的解決思路和C++完全不一樣,Python使用的是super

我們把第2章的鉆石繼承用super重寫一下,看一下輸出結果

class Base(object):def __init__(self):print “Base init”class Medium1(Base):def __init__(self):super(Medium1, self).__init__()print “Medium1 init”class Medium2(Base):def __init__(self):super(Medium2, self).__init__()print “Medium2 init”class Leaf(Medium1, Medium2):def __init__(self):super(Leaf, self).__init__()print “Leaf init”

我們生成Leaf對象:

>>> leaf = Leaf()

Base init

Medium2 init

Medium1 init

Leaf init

可以看到整個初始化過程符合我們的預期,Base只被初始化了1次。而且重要的是,相比原來的普通寫法,super方法并沒有寫額外的代碼,也沒有引入額外的概念

4.?? super的內核:mro

要理解super的原理,就要先了解mro。mro是method resolution order的縮寫,表示了類繼承體系中的成員解析順序。

?

在python中,每個類都有一個mro的類方法。我們來看一下鉆石繼承中,Leaf類的mro是什么樣子的:

>>> Leaf.mro()

[<class '__main__.Leaf'>, <class '__main__.Medium1'>, <class '__main__.Medium2'>, <class '__main__.Base'>, <type 'object'>]

?

可以看到mro方法返回的是一個祖先類的列表。Leaf的每個祖先都在其中出現一次,這也是super在父類中查找成員的順序。?

通過mro,python巧妙地將多繼承的圖結構,轉變為list的順序結構。super在繼承體系中向上的查找過程,變成了在mro中向右的線性查找過程,任何類都只會被處理一次。

?

通過這個方法,python解決了多繼承中的2大難題:

1. 查找順序問題。從Leaf的mro順序可以看出,如果Leaf類通過super來訪問父類成員,那么Medium1的成員會在Medium2之前被首先訪問到。如果Medium1和Medium2都沒有找到,最后再到Base中查找。

2. 鉆石繼承的多次初始化問題。在mro的list中,Base類只出現了一次。事實上任何類都只會在mro list中出現一次。這就確保了super向上調用的過程中,任何祖先類的方法都只會被執行一次。

?

至于mro的生成算法,可以參考這篇wiki:https://en.wikipedia.org/wiki/C3_linearization

5.?? super的具體用法

我們首先來看一下python中的super文檔

>>> help(super)

Help on class super in module __builtin__:

class super(object)

?|? 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)

?

光從字面來看,這可以算是python中最語焉不詳的幫助文檔之一了。甚至里面還有一些術語誤用。那super究竟應該怎么用呢,我們重點來看super中的第1和第3種用法

5.1. super(type, obj)

當我們在Leaf的__init__中寫這樣的super時:

class Leaf(Medium1, Medium2):def __init__(self):super(Leaf, self).__init__()print “Leaf init”

super(Leaf, self).__init__()的意思是說:

  • 獲取self所屬類的mro, 也就是[Leaf, Medium1, Medium2, Base]
  • 從mro中Leaf右邊的一個類開始,依次尋找__init__函數。這里是從Medium1開始尋找
  • 一旦找到,就把找到的__init__函數綁定到self對象,并返回
  • ?

    從這個執行流程可以看到,如果我們不想調用Medium1的__init__,而想要調用Medium2的__init__,那么super應該寫成:super(Medium1, self)__init__()?

    5.2. super(type, type2)

    當我們在Leaf中寫類方法的super時:

    class Leaf(Medium1, Medium2):def __new__(cls):obj = super(Leaf, cls).__new__(cls)print “Leaf new”return obj

    super(Leaf, cls).__new__(cls)的意思是說:

  • 獲取cls這個類的mro,這里也是[Leaf, Medium1, Medium2, Base]
  • 從mro中Leaf右邊的一個類開始,依次尋找__new__函數
  • 一旦找到,就返回“非綁定”的__new__函數
  • ?

    由于返回的是非綁定的函數對象,因此調用時不能省略函數的第一個參數。這也是這里調用__new__時,需要傳入參數cls的原因

    同樣的,如果我們想從某個mro的某個位置開始查找,只需要修改super的第一個參數就行

    6.?? 小結

    至此,我們講解了和super相關的用法及原理,小結一下我們講過的內容有:

  • python調用父類成員共有2種方法:普通方法,super方法
  • 在鉆石繼承中,普通方法會遇到Base類兩次初始化的問題
  • 簡述了其他語言對這個問題的解決方法,并用實例展示了python使用super可以解決此問題
  • 在講super具體用法前,先講了super的內核:mro的知識和原理
  • 講解了super兩種主要的用法及原理
  • ?

    標簽:python, super, mro, 多繼承

    轉載于:https://www.cnblogs.com/testview/p/4651198.html

    總結

    以上是生活随笔為你收集整理的深入super,看Python如何解决钻石继承难题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 成人免费视频国产免费麻豆 | 亚洲精品高清视频在线观看 | 麻豆精品久久久久久久99蜜桃 | 国产极品粉嫩 | 成人三级晚上看 | 日韩福利视频 | 亚洲人成网站999久久久综合 | 黄色一级欧美 | 日本精品黄 | 少妇第一次交换又紧又爽 | 特淫毛片 | 日韩一级在线 | 青青青在线视频 | 琪琪免费视频 | 男人的网址 | 亚洲av成人精品日韩在线播放 | 国产精品一区二区亚洲 | 性视屏| 特黄特色大片免费视频大全 | 精品黄色av | 在线精品免费视频 | 色翁荡息又大又硬又粗又爽 | 捆绑无遮挡打光屁股调教女仆 | 日韩精品一区二区在线看 | 九一国产在线观看 | 中文字幕免费高清在线观看 | 午夜爱爱影院 | 播金莲一级淫片aaaaaaa | 免费人成年激情视频在线观看 | 天天爱综合网 | 青青操在线视频 | 日韩91精品 | 69国产成人精品二区 | 国产黄片一区二区三区 | 女人做爰全过程免费观看美女 | 瑟瑟视频免费看 | 在线免费看av | 91蝌蚪91九色白浆 | 欧美激情视频一区二区 | 久久久久久逼 | 日韩av无码一区二区三区不卡 | 少妇又色又爽又黄的视频 | 免费看污黄网站在线观看 | 啪一啪在线 | 久久国产精品无码一区二区 | 99国产成人精品 | 亚洲av综合色区无码一区 | 91av在线网站 | 国产一区二区播放 | 国产丝袜美腿一区二区三区 | 偷拍亚洲| 在线观看视频一区 | av青娱乐 | 野花中文免费观看6 | 久久久永久久久人妻精品麻豆 | 日韩精品久久久久久免费 | 青青草国内自拍 | 国产偷国产偷av亚洲清高 | 韩国美女福利视频 | 亚洲第一页视频 | 久久盗摄| 婷婷调教口舌奴ⅴk | 亚洲欧美精品一区二区 | 91精品人妻一区二区三区蜜桃欧美 | 色多多导航 | 亚洲av无一区二区三区怡春院 | 色日韩 | 国产色片在线观看 | 亚洲va国产va天堂va久久 | 青青草色视频 | 特黄aaaaaaaaa毛片免费视频 | 丰满白嫩尤物一区二区 | 日韩精品一区二区亚洲av性色 | 黄色大片在线看 | 欧美一区二区高清 | 91丨九色丨蝌蚪丨丝袜 | 激情四射综合网 | 百合sm惩罚室羞辱调教 | 中文字幕在线字幕中文 | 久久精品国产一区二区电影 | 国产91视频播放 | 在线观看免费av网站 | 日韩在线观看精品 | 肉丝美脚视频一区二区 | 午夜xxx| 久久久久久久美女 | 中文在线天堂网 | 乌克兰性极品xxxhd | 欧美日韩亚洲精品一区二区 | 欧美二区视频 | 成人图片小说 | 国产精品桃色 | 四川丰满妇女毛片四川话 | 色 综合 欧美 亚洲 国产 | 国产精品自拍偷拍视频 | 国产精品理论片在线观看 | 日韩乱码人妻无码中文字幕 | 无码成人一区二区 | 99久久精品免费视频 |