摘要:繼承的優(yōu)缺點(diǎn)推出繼承的初衷是讓新手順利使用只有專家才能設(shè)計(jì)出來的框架。多重繼承的真實(shí)應(yīng)用多重繼承能發(fā)揮積極作用。即便是單繼承,這個(gè)原則也能提升靈活性,因?yàn)樽宇惢且环N緊耦合,而且較高的繼承樹容易倒。
繼承的優(yōu)缺點(diǎn)
推出繼承的初衷是讓新手順利使用只有專家才能設(shè)計(jì)出來的框架。
——Alan Kay
直接子類化內(nèi)置類型(如 dict、list 或 str)容易出錯(cuò),因?yàn)閮?nèi)置類型的 方法通常會(huì)忽略用戶覆蓋的方法。
不要子類化內(nèi)置類型,用戶自己定義的類應(yīng)該繼承 collections 模塊的類,
例如UserDict、UserList 和 UserString,這些類做了特殊設(shè)計(jì),因此易于擴(kuò)展。
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"])
綜上,本節(jié)所述的問題只發(fā)生在 C 語言實(shí)現(xiàn)的內(nèi)置類型內(nèi)部的方法委托上,而且只影響 直接繼承內(nèi)置類型的用戶自定義類。
如果子類化使用 Python 編寫的類,如 UserDict 或 MutableMapping,就不會(huì)受此影響。
多重繼承和方法解析順序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) #看繼承關(guān)系 print(D.__mro__)
直接調(diào)用 d.pong() 運(yùn)行的是 B 類中的版本。
Python 能區(qū)分 d.pong() 調(diào)用的是哪個(gè)方法,是因?yàn)?Python 會(huì)按照特定的順序遍歷繼承圖。
這個(gè)順序叫方法解析順序(Method Resolution Order,MRO)。
類都有一個(gè)名為__mro__ 的屬性,它的值是一個(gè)元組,按照方法解析順序列出各個(gè)超類,從當(dāng)前類一直向上,直到 object 類。D
然而,使用 super() 最安全,也不易過時(shí)。調(diào)用框架或不受自己控制的類層次結(jié)構(gòu)中的
方法時(shí),尤其適合使用 super()。
1 多重繼承能發(fā)揮積極作用。
2 《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書中的適配器模式用的就是多重繼承,因此使用多重繼承肯定沒有錯(cuò)
3(那本書中的其他 22 個(gè)設(shè)計(jì)模式都使用單繼承,因此多重繼承顯然不是靈丹妙藥)
下面是避免把類圖攪亂的一些建議。
01. 把接口繼承和實(shí)現(xiàn)繼承區(qū)分開使用多重繼承時(shí),一定要明確一開始為什么創(chuàng)建子類。主要原因可能有:
繼承接口,創(chuàng)建子類型,實(shí)現(xiàn)“是什么”關(guān)系
繼承實(shí)現(xiàn),通過重用避免代碼重復(fù)
其實(shí)這兩條經(jīng)常同時(shí)出現(xiàn),不過只要可能,一定要明確意圖。通過繼承重用代碼是實(shí)
現(xiàn)細(xì)節(jié),通常可以換用組合和委托模式。而接口繼承則是框架的支柱。
現(xiàn)代的 Python 中,如果類的作用是定義接口,應(yīng)該明確把它定義為抽象基類。Python
3.4 及以上的版本中,我們要?jiǎng)?chuàng)建 abc.ABC 或其他抽象基類的子類
python沒有interface這種定義
03. 通過混入重用代碼一個(gè)類的作用是為多個(gè)不相關(guān)的子類提供方法實(shí)現(xiàn)
應(yīng)該把那個(gè)類明確地定義為混入類(mixin class)
從概念上講,混入不定義新類型,只是打包方法,便于重用。
混入類絕對(duì)不能實(shí)例化,而且具體類不能只繼承混入類。
混入類應(yīng)該提供某方面的特定行為,只實(shí)現(xiàn)少量關(guān)系非常緊密的方法。
04. 在名稱中明確指明混入因?yàn)樵?Python 中沒有把類聲明為混入的正規(guī)方式,所以強(qiáng)烈推薦在名稱中加入...Mixin 后綴。
Tkinter 沒有采納這個(gè)建議,如果采納的話,XView 會(huì)變成XViewMixin,Pack 會(huì)變成 PackMixin
05. 為用戶提供聚合類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 類的定義體是空的,但是這個(gè)類提供了有用的服務(wù):
把四個(gè)超類結(jié)合在一起,這樣需要?jiǎng)?chuàng)建新小組件的用戶無需記住全部混入,也不用擔(dān)心聲明 class 語句時(shí)有沒有遵守特定的順序。08. “優(yōu)先使用對(duì)象組合,而不是類繼承”
這句話引自《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書, 這是我能提供的最佳
建議。
熟悉繼承之后,就太容易過度使用它了。出于對(duì)秩序的訴求,我們喜歡按整潔
的層次結(jié)構(gòu)放置物品,程序員更是樂此不疲。
即便是單繼承,這個(gè)原則也能提升靈活性,因?yàn)樽宇惢?br>一種緊耦合,而且較高的繼承樹容易倒。繼承在Django的應(yīng)用
page 417 這里有些復(fù)雜,等我牛掰了再來看
總結(jié)collections.abc 模塊中相應(yīng)的抽象基類
多重繼承這把雙刃劍。首先,我們說明了 mro 類屬性中蘊(yùn)藏的方法解析順序,有了這一機(jī)制,繼承方法的名稱不再會(huì)發(fā)生沖突
不要子類化內(nèi)置類型,用戶自己定義的類應(yīng)該繼承 collections 模塊的類
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/44726.html
摘要:例如,的序列協(xié)議只需要和兩個(gè)方法。任何類如,只要使用標(biāo)準(zhǔn)的簽名和語義實(shí)現(xiàn)了這兩個(gè)方法,就能用在任何期待序列的地方。方法開放了內(nèi)置序列實(shí)現(xiàn)的棘手邏輯,用于優(yōu)雅地處理缺失索引和負(fù)數(shù)索引,以及長度超過目標(biāo)序列的切片。 序列的修改、散列和切片 接著造Vector2d類 要達(dá)到的要求 為了編寫Vector(3, 4) 和 Vector(3, 4, 5) 這樣的代碼,我們可以讓 init 法接受任...
摘要:自己定義的抽象基類要繼承。抽象基類可以包含具體方法。這里想表達(dá)的觀點(diǎn)是我們可以偷懶,直接從抽象基類中繼承不是那么理想的具體方法。 抽象基類 抽象基類的常見用途: 實(shí)現(xiàn)接口時(shí)作為超類使用。 然后,說明抽象基類如何檢查具體子類是否符合接口定義,以及如何使用注冊(cè)機(jī)制聲明一個(gè)類實(shí)現(xiàn)了某個(gè)接口,而不進(jìn)行子類化操作。 如何讓抽象基類自動(dòng)識(shí)別任何符合接口的類——不進(jìn)行子類化或注冊(cè)。 接口在動(dòng)態(tài)類...
摘要:但返回的是一個(gè)類型的對(duì)象,這意味著操作的結(jié)果是一個(gè)類型的對(duì)象。反之,如果對(duì)象存在,這次調(diào)用就會(huì)將其作為函數(shù)的輸入,并按照與方法的約定返回一個(gè)對(duì)象。 一、Optional 類入門 Java 8中引入了一個(gè)新的類java.util.Optional。變量存在時(shí),Optional類只是對(duì)類簡單封裝。變量不存在時(shí),缺失的值會(huì)被建模成一個(gè)空的Optional對(duì)象,由方法Optional.empt...
摘要:小總結(jié)標(biāo)準(zhǔn)庫里的所有映射類型都是利用來實(shí)現(xiàn)只有可散列的數(shù)據(jù)類型才能用作這些映射里的鍵值不用字典推導(dǎo)用處理找不到的鍵找不到鍵返回某種默認(rèn)值底層是與調(diào)用實(shí)現(xiàn)的字典插入更新原理其他大多數(shù)映射類型都提供了兩個(gè)很強(qiáng)大的方法和。 字典和集合 標(biāo)準(zhǔn)庫里的所有映射類型都是利用 dict 來實(shí)現(xiàn)的只有可散列的數(shù)據(jù)類型才能用作這些映射里的鍵(值不用) 可散列 一個(gè)對(duì)象是可散列的 它的散列值是不變的 對(duì)象...
摘要:第一章數(shù)據(jù)類型隱式方法利用快速生成類方法方法通過下標(biāo)找元素自動(dòng)支持切片操作可迭代方法與如果是一個(gè)自定義類的對(duì)象,那么會(huì)自己去調(diào)用其中由你實(shí)現(xiàn)的方法。若返回,則會(huì)返回否則返回。一個(gè)對(duì)象沒有函數(shù),解釋器會(huì)用作為替代。 第一章 python數(shù)據(jù)類型 1 隱式方法 利用collections.namedtuple 快速生成類 import collections Card = collec...
閱讀 2694·2021-11-18 10:02
閱讀 2688·2021-11-15 11:38
閱讀 3796·2021-11-12 10:36
閱讀 767·2021-11-12 10:34
閱讀 2998·2021-10-21 09:38
閱讀 1600·2021-09-29 09:48
閱讀 1708·2021-09-29 09:34
閱讀 1187·2021-09-22 10:02