<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近在看sanic的原始碼,發現有很多Mixin的類,大概長成這個樣子
class BaseSanic( RouteMixin, MiddlewareMixin, ListenerMixin, ExceptionMixin, SignalMixin, metaclass=SanicMeta, ):
於是對於這種 Mixin 研究了一下,其實也沒什麼新的東西,Mixin 又稱混入,只是一種程式設計思想的體現,但是在使用過程中還是有一些需要注意的地方。 大家都知道,python 是一種允許多繼承的語言,一個類可以繼承多個類,這和java不太一樣,java類只能有一個父類別, 但是java 中有介面的概念,一個類可以實現多個介面,但是java的介面只是定義的函數的簽名,並沒有具體的實現,具體的實現需要相應的類來完成。 python 就不一樣了,一個類可以有多個父類別,而混入類就是這種允許多繼承語言中才有的一種程式設計模式。 為了更好的理解混入,我們舉一個生活中的例子---手機, 手機有很多功能,由不同的硬體組合而成,手機有接打電話,收傳簡訊,上網,聽歌等功能,組裝一臺手機就需要將各種硬體進行拼接。 如果我們把這些功能抽象成類,那麼我們可以有以下寫法,為了簡單一點,只列接打電話,收傳簡訊功能。
class Tel: def telfunc(self): print("我可以接打電話") class SMS: def smsfunc(self): print("我可以傳簡訊") class Phone: def __init__(self, sn): self.sn = sn
上面的程式碼中, 有三個類,Tel 類,它有一個 telfunc
方法用於表示有接打電話的能力(或者說是功能), SMS 類有smsfunc
表示SMS類有傳簡訊的能力。 而 Phone 這個類才是一個手機類,它應該具有接打電話和傳送簡訊的能力,但是如果我們用上面的方式定義Phone 這個類,則這個類並沒有接打電話和收傳簡訊的能力。 我們可以怎樣做讓Phone這個類可以具有打電話和傳簡訊的能力? 我們可以在Phone 這個類裡再重新定義二個方法 telfunc
和 smsfunc
,也就是將Tel類和SMS類裡的方法再寫一遍,這種其實不符合 don't repeate youself
的理念。 正常情況下我們是讓Phone這個類繼承Tel類和SMS類,這樣Phone這個類就自動擁有了接打電話和傳簡訊的能力了。
class Tel: def telfunc(self): print("我可以接打電話") class SMS: def smsfunc(self): print("我可以傳簡訊") class Phone(Tel, SMS): def __init__(self, sn): self.sn = sn def welcome(self): print("welcome {}".format(self.sn)) p = Phone("xiaomi") p.telfunc() p.smsfunc() p.welcome() ''' 我可以接打電話 我可以傳簡訊 welcome xiaomi '''
像這種類的定義就是我們所說的混入,將通話功能與簡訊功能加入到手機中,讓手機擁有接打電話和傳送簡訊的功能,這種混入的編碼思想有時可以減少很多程式碼量。很方便的根據一個類需要哪些功能就將哪個類“混入”到該類中。 通常情況下,我們會將混入類的命名以Mixin結尾,像上面的程式碼我們會寫成下面這樣
class TelMixin: def telfunc(self): print("我可以接打電話") class SMSMixin: def smsfunc(self): print("我可以傳簡訊") class Phone(TelMixin, SMSMixin): def __init__(self, sn): self.sn = sn def welcome(self): print("welcome {}".format(self.sn))
以 Mixin 結尾的類,一般是那種功能比較單一,且一般都是某一型別的功能, 如最開始介紹的sanic混入類 RouteMixin 與路由相關的功能類,MiddlewareMixin 是與中介軟體相關的類,ListenerMixin 是監聽器相關的類,這些類裡的方法專注於自己相關的功能,如果有哪個類需要這些功能,那定義的時候就繼承自這些類。
有人會問了,我不想多繼承,管理MRO 太麻煩了,我只想單繼承,我定義一個統一的父類別,它即有接打電話,也有收傳簡訊的功能,還可以聽歌,然後讓手機來繼承這個類不好嗎?
如下面的程式碼:
class Tel: def telfunc(self): print("我可以接打電話") def smsfunc(self): print("我可以傳簡訊") def songfunc(self): print("我可以放音樂") class Phone(Tel): def __init__(self, sn): self.sn = sn def welcome(self): print("welcome {}".format(self.sn))
首先這種寫法當然是可以的,語法上沒有任何問題,也很好的實現了相應的功能,程式碼量也減少了,但是這裡大家想一個邏輯問題,如果我想造一個ipod類,ipod 這個類沒有接打電話收傳簡訊的功能,只有聽歌的功能,那麼我此時要寫這個類該如何定義? 是不是要定義一個ipod類,然後再寫它的聽歌方法songfunc,如果此時使用混入的程式設計思想,那麼我們就完全可以定義ipod類的時候 不加入 接打電話和收傳簡訊的類就可以了。
class TelMixin: def telfunc(self): print("我可以接打電話") class SMSMixin: def smsfunc(self): print("我可以傳簡訊") class SongMixin: def songfunc(self): print("我可以放音樂") class Phone(TelMixin, SMSMixin, SongMixin): def __init__(self, sn): self.sn = sn class Ipod(SongMixin): def __init__(self, sn): self.sn = sn
如果還有別的什麼類,比如對講機,它只有接打電話的功能,那麼我們就只需要把接打電話的功能混入到對講機類即可, class Intercom(TelMixin):
但是有人又會問了,這樣的混入,雖說少寫了一些程式碼,但是如果子類相應實現並不完全和父類別一致該如何處理? 如對講機雖然可以通話,但是它是單向通話,並不能雙向通話的。 這時對於子類實現與父類別不一致的情況,那麼就需要子類重寫父類別方法了,也就是OOP中的繼承與多型,嚴格意義上來說, python 並沒有多型,或者說它天然的就是多型。
class TelMixin: def telfunc(self): print("我可以接打電話") class SMSMixin: def smsfunc(self): print("我可以傳簡訊") class SongMixin: def songfunc(self): print("我可以放音樂") class Intercom(TelMixin): def __init__(self, sn): self.sn = sn def telfunc(self): print("對講機{} 的通話".format(self.sn)) class Phone(TelMixin, SMSMixin, SongMixin): def __init__(self, sn): self.sn = sn class Ipod(SongMixin): def __init__(self, sn): self.sn = sn def testTelfunc(o): o.telfunc() d = Intercom("moto") p = Phone("huawei") ipod = Ipod("apple") testTelfunc(d) testTelfunc(p) testTelfunc(ipod)
以上程式碼,我們重寫了對講機類的telfunc 方法,但是並沒有對Ipod類實現通話功能, 然後寫了一個testTelfunc(o)
方法來呼叫傳入引數的通話功能,
得到以下輸出:
#對講機moto 的通話
#我可以接打電話
Traceback (most recent call last):
File "/Users/yyx/test/test.py", line 54, in <module>
testTelfunc(ipod)
File "/Users/yyx/test/test.py", line 46, in testTelfunc
o.telfunc()
AttributeError: 'Ipod' object has no attribute 'telfunc'
當給testTelfunc 傳入的是對講機Intercom 物件時,由於該類重寫了telfunc方法,所以這裡呼叫的是該子類的telfunc方法,當傳入的是Phone類物件時,由於該類繼承了TelMixin類,且沒有重寫telfunc方法,所以這裡會呼叫TelMixin類中的telfunc 方法,但是當傳入的是Ipod類時,這個類既沒有繼承TelMixin,也沒有自己的telfunc方法,所以就崩潰了。這也是一種另類的多型體現吧,只是它沒有像java中的那麼嚴格。
說了那麼多的Mixin混入,其實它本質上就是繼承,只是這種繼承是存在於允許多繼承的程式語言中,如果說區別,本質上也沒有什麼區別,如果硬是要說些區別,其實也是有一點點。
__init__
方法,因為如果Mixin類定義了初始化方法,那麼在子類中也最好呼叫一下父類別也就是混入類的初始方法super().__init__()
,當然不呼叫也沒關係,IDE 只會給你一個提示,語法上並沒有什麼錯誤。說了那麼多Mixin 的好處,它有什麼不好的地方嗎? 其實在我看來,有一個問題,也說不上是不好,只是習慣問題,以前寫程式碼還是寫單繼承多一些,並不太習慣這種多繼承的方式,不過如果一切都按照相應的規則來操作也不是什麼大問題。 還有一個問題就是功能的拆分,這個很是考驗程式設計人員在設計程式碼之初整體把握能力,就像單體應用想要拆分成微服務,邊界問題可能是開始時最頭疼的,拆細了吧,會寫出很多類,拆粗了吧,就又回到單繼承的思維模式了,所以這個也是個經驗問題吧。
Mixin 混入也可以說是程式設計模式,並不是什麼新的語法,用好混入類可以使自己的程式碼結構清晰,功能明瞭,所以以後在設計類時要多考慮使用Mixin混入類的實現方式。
到此這篇關於python 中Mixin混入類的使用方法詳解的文章就介紹到這了,更多相關python Mixin混入類內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45