1、不要試圖在內建型別的子類中重寫方法,可以繼承collections的可拓展類尋求變通;1、內建型別的方法不會呼叫子類覆蓋的方法2、掌握多重繼承中的mro和super;
3、了解處理多重繼承的一些建議。
內建類可以子類化,但是內建型別的方法不會呼叫子類覆蓋的方法。
下面以繼承dict的自定義子類重寫__setitem__為例說明:
class modifieddict(dict):
def __setitem__(self, key, value):
super().__setitem__(key,[value]*2)
a=modifieddict(one=1)
a["two"]=2
print(a)
a.update(three=3)
print(a)#輸出
從輸出可以看到,鍵值對one=1和three=3存入a時均呼叫了dict的__setitem__,只有運算子會呼叫我們預先覆蓋的方法。
問題的解決方式在於不去子類化dict,而是子類化colections.userdict。
2、子類化collections中的類
使用者自定義的類應該繼承collections模組,如userdict,userlist,userstring。這些類做了特殊設計,因此易於拓展。
子類化userdict的**如下:
from collections import userdict
class modifieddict(userdict):
def __setitem__(self, key, value):
super().__setitem__(key,[value]*2)
b=modifieddict(one=1)
b["two"]=2
b.update(three=3)
print(b)#輸出
1、方法解析順序(method resolution order,mro)
在多重繼承中存在不相關的祖先類實現同名方法引起的衝突問題,這種問題稱作「菱形問題」。python依靠特定的順序遍歷繼承圖,這個順序叫做方法解析順序。如圖,左圖是類的uml圖,右圖中的虛線箭頭是方法解析順序。
提到類的屬性__mro__,就會提到super:
super 是個類,既不是關鍵字也不是函式等其他資料結構。作用:super是子類用來呼叫父類方法的。
語法:super(a_type, obj);
a_type是obj的__mro__,當然也可以是__mro__的一部分,同時issubclass(obj,a_type)==true
舉個例子, 有個 mro: [a, b, c, d, e, object]
我們這樣呼叫:super(c, a).foo()
super 只會從 c 之後查詢,即: 只會在 d 或 e 或 object 中查詢 foo 方法。
下面構造乙個菱形問題的多重繼承來深化理解:
class a:
def ping(self):
print("a-ping:",self)
class b(a):
def pong(self):
print("b-pong:",self)
class c(a):
def pong(self):
print("c-pong:",self)
class d(b, c):
def ping(self):
print("d-ping:",self)
super().ping()
def pingpong(self):
self.ping()
super().ping()
self.pong()
super(b,d).pong(self)
d=d()
d.pingpong()
print(d.mro())
輸出如下:
d-ping: <__main__.d object at>
a-ping: <__main__.d object at>#前兩行對應self.ping()。
a-ping: <__main__.d object at>#此處super呼叫父類的ping方法。
b-pong: <__main__.d object at>
c-pong: <__main__.d object at>#此處從b之後搜尋父類的pong()
[, , , , ]#類d的__mro__,資料以元組的形式儲存。
分析:d.pingpong()執行super.ping(),super按照mro查詢父類的ping方法,查詢在類b到ping之後輸出了b.ping()。
3、處理多重繼承的建議
(1)把介面繼承和實現繼承區分開;
(2)使用抽象基類顯式表示介面;
(3)通過混入重用**;
混入類為多個不相關的子類提供方法實現,便於重用,但不會例項化。並且具體類不能只繼承混入類。
(4)在名稱中明確指明混入;
python中沒有把類宣告為混入的正規方式,luciano推薦在名稱中加入mixin字尾。如tkinter中的xview應變成xviewmixin。
(5)抽象基類可以作為混入,反過來則不成立;
抽象基類與混入的異同:
(6)不要子類化多個具體類;
具體類可以沒有,或者至多乙個具體超類。
例如,class dish(china,japan,tofu)中,如果tofu是具體類,那麼china和japan必須是抽象基類或混入。
(7)為使用者提供聚合類;
聚合類是指乙個類的結構主要繼承自混入,自身沒有新增結構或行為。tkinter採納了此條建議。
(8)優先使用物件組合,而不是類繼承。
優先使用組合可以令設計更靈活。
組合和委託可以代替混入,但不能取代介面繼承去定義型別層次結構。
流暢的Python 繼承的優缺點
1.子類化內建型別很麻煩 在python3中,內建型別可以子類化,但是有個重要的注意事項 內建型別 cpython 不會呼叫使用者定義的類覆蓋的特殊方法。內建型別的方法不會呼叫子類覆蓋的方法。例如,dict 的子類覆蓋的 getitem 方法不會被內建型別的get 方法呼叫。class doppel...
組合 繼承的優缺點
組合的優點和缺點 n 優點 f 容器類僅能通過被包含物件的介面來對其進行訪問。f 黑盒 復用,因為被包含物件的內部細節對外是不可見。f 對裝性好。f 實現上的相互依賴性比較小。譯者注 被包含物件與容器物件之間的依賴關係比較少 f 每乙個類只專注於一項任務。f 通過獲取指向其它的具有相同型別的物件引用...
Python的優缺點
python是著名的 龜叔 guido van rossum在1989年聖誕節期間,為了打發無聊的聖誕節而編寫的乙個程式語言。最後說說python的缺點。任何程式語言都有缺點,python也不例外。優點說過了,那python有哪些缺點呢?第乙個缺點就是執行速度慢,和c程式相比非常慢,因為python...