推出繼承的初衷是讓新手順利使用只有專家才能設計出來的框架。
——Alan Kaypython
import collections class DoppelDict2(collections.UserDict): def __setitem__(self, key, value): super().__setitem__(key, [value] * 2) dd = DoppelDict2(one=1) print(dd) dd['two'] = 2 print(dd) dd.update(three=3) print(dd) class AnswerDict2(collections.UserDict): def __getitem__(self, key): return 42 ad = AnswerDict2(a='foo') print(ad["a"])
class A: def ping(self): print('ping:', self) class B(A): def pong(self): print('pong:', self) class C(A): def pong(self): print('PONG:', self) class D(B, C): def ping(self): super().ping() print('post-ping:', self) def pingpong(self): self.ping() super().ping() self.pong() super().pong() C.pong(self) d = D() d.pong() C.pong(d) #看繼承關係 print(D.__mro__)
直接調用 d.pong() 運行的是 B 類中的版本。程序員
Python 能區分 d.pong() 調用的是哪一個方法,是由於 Python 會按照特定的順序遍歷繼承圖。
這個順序叫方法解析順序(Method Resolution Order,MRO)。
類都有一個名爲__mro__ 的屬性,它的值是一個元組,按照方法解析順序列出各個超類,從當前類一直向上,直到 object 類。D
然而,使用 super() 最安全,也不易過期。調用框架或不受本身控制的類層次結構中的
方法時,尤爲適合使用 super()。設計模式
1 多重繼承能發揮積極做用。
2 《設計模式:可複用面向對象軟件的基礎》一書中的適配器模式用的就是多重繼承,所以使用多重繼承確定沒有錯
3(那本書中的其餘 22 個設計模式都使用單繼承,所以多重繼承顯然不是靈丹妙藥)安全
下面是避免把類圖攪亂的一些建議。app
使用多重繼承時,必定要明確一開始爲何建立子類。主要緣由可能有:框架
繼承接口,建立子類型,實現「是什麼」關係
繼承實現,經過重用避免代碼重複
其實這兩條常常同時出現,不過只要可能,必定要明確意圖。經過繼承重用代碼是實
現細節,一般能夠換用組合和委託模式。而接口繼承則是框架的支柱。post
現代的 Python 中,若是類的做用是定義接口,應該明確把它定義爲抽象基類。Python
3.4 及以上的版本中,咱們要建立 abc.ABC 或其餘抽象基類的子類
python沒有interface這種定義設計
class Widget(BaseWidget, Pack, Place, Grid): """Internal class. Base class for a widget which can be positioned with the geometry managers Pack, Place or Grid.""" pass
Widget 類的定義體是空的,可是這個類提供了有用的服務:code
把四個超類結合在一塊兒,這樣須要建立新小組件的用戶無需記住所有混入,也不用擔憂聲明 class 語句時有沒有遵照特定的順序。
這句話引自《設計模式:可複用面向對象軟件的基礎》一書, 這是我能提供的最佳
建議。對象
熟悉繼承以後,就太容易過分使用它了。出於對秩序的訴求,咱們喜歡按整潔
的層次結構放置物品,程序員更是樂此不疲。
即使是單繼承,這個原則也能提高靈活性,由於子類化是
一種緊耦合,並且較高的繼承樹容易倒。
page 417 這裏有些複雜,等我牛掰了再來看
collections.abc 模塊中相應的抽象基類
多重繼承這把雙刃劍。首先,咱們說明了 mro 類屬性中蘊藏的方法解析順序,有了這一機制,繼承方法的名稱再也不會發生衝突不要子類化內置類型,用戶本身定義的類應該繼承 collections 模塊的類