Python中的Mixin详解
一些閑聊:
Mixin是一種設計模式、設計思想
并不是某個特定的class或者函數.
Java中的Mixin叫interface
Ruby中的Mixin叫Module
[2]優點:
1.mixin設計迷失可以在不對類的內容的修改前提下,擴展類的功能(添加父類)
2.更加方便的組織和維護不同的組建
3.可以根據開發需要任意調整功能
4.可以避免產生更多的類
缺點:
受繼承關系限制,推薦只有兩層的繼承使用。
#-------------------------------------------------
案例一[3]:
class Role:def walk(self):print('走')#--------------------------------------------------------------- class RunMixin:def run(self):print('跑')class PromptSkillMixin:def use_prompt_skill(self):print('使用了一個瞬發技能')class WalkExMixin:#覆蓋Role中的功能,因為下面是最先繼承,Role是最后繼承def walk(self):print('疾走')class RoleEx(WalkExMixin, PromptSkillMixin, RunMixin, Role):def marco(self):return [self.run, self.use_prompt_skill]def use_marco(self):print("---------------use_marco技術----------------")for action in self.marco():action()print("--------use_marco結束----------") if __name__ == '__main__':r = RoleEx()r.use_marco()r.walk()實驗結果:
---------------use_marco技術----------------
跑
使用了一個瞬發技能
--------use_marco結束------------------
疾走
?
這個案例顯而易見的好處是:
你在不用修改Role的情況下擴展了很多功能.
因為有的時候,Role這個是由你的同事開發的,你沒有修改的權限,你的同事僅僅給了你調用接口的權限,
或者說,為了免責和穩定,比如到時候出問題誰背鍋啊,你不被公司允許修改原來的代碼.
#------------------------------------------------
案例二[1]:
class Displayer():def display(self, message):print("--------②這里是Displayer.display函數---start-----")print("Displayer的self=",self)print(message)print("--------②這里是Displayer.display函數---end-----\n")class LoggerMixin():def log(self, message, filename='logfile.txt'):print("MySubClass self=",self)with open(filename, 'a') as fh:print("--------③這里是LoggerMixin.log函數---start-----")fh.write(message)print("--------③這里是LoggerMixin.log函數---end-----\n")def display(self, message):print("display的self=",self)#這里的self類指代的是MySubClass,并不是LoggerMixinprint("------①這里是LoggerMixin的display函數-start--\n")super().display(message)#會調用Displayer.display()函數self.log(message)print("------①這里是LoggerMixin的display函數-end--\n")class MySubClass(LoggerMixin, Displayer):def log(self, message):super().log(message, filename='subclasslog.txt')subclass = MySubClass() subclass.display("This string will be shown and logged in subclasslog.txt")''' 1. MySubClass.display() is resolved to LoggerMixin.display(). MySubClass.display() 方法被解析為 LoggerMixin.display() 方法的調用。 這應該還是比較好理解的。因為對于 MySubClass 類來說, 在繼承鏈上的兩個父類,LoggerMixin 和 Displayer 來說,LoggerMixin 是最近的,因此調用它的 display() 方法。2. LoggerMixin.display() calls super().display(), which is resolved to Displayer.display(). LoggerMixin.display() 方法調用了 super().display(),這一行代碼按照我們剛才的解釋,查看 MySubClass 的繼承鏈, 是應該調用 Displayer 類的 display() 方法的。這一步是相對來說比較難以理解的。讓我們這么來理解它,當 LoggerMixin.display() 中調用了 super().display() 的時候,它會嘗試去尋找屬于當前類的繼承鏈。而這個當前類是什么類呢? 不是 LoggerMixin 類,而是 MySubClass 類。MySubClass 類的繼承連是 LoggerMixin,然后 Displayer。所以,我們就找到了 Displayer 的 display() 方法。3. It alse calls self.log(). Since self, in this case, is a MySubClass instance, it resolves to MySubClass.log(). MySubClass.log() calls super().log(), which is resolved back to LoggerMixin.log(). 別忘了,我們的 LoggerMixin 類還調用了 self.log() 方法。 這個看似好像要直接調用 LoggerMixin 的 log 方法,其實不然。LoggerMixin 的 display() 方法在當前語境中的 self,其實是 MySubClass 類的對象, 因此對于 MySubClass 類的對象,想要調用 log 方法, 是直接調用自己類中的 log 方法,也就是 MySubClass.log() 方法,而不是 LoggerMixin.log() 方法的。而又因為 MySubClass.log() 方法調用了 super().log() 方法,這才根據繼承鏈尋找最近的父類,才找到了 LoggerMixin 類中的 log() 方法進行調用。這個例子在網上非常有名,[1]中分析了這個例子的細節,細節我已經都復制到上方的代碼中了.
核心思想和目標是(個人分析):
假如沒有LoggerMixin,這個代碼就剩下Displayer,所以整體代碼的目標是:
不修改Displayer的情況下(這個非常重要),擴充Displayer的功能.
#---------------案例二[1]實驗結果-感性分析-------------------------
實驗結果如下:
display的self= <__main__.MySubClass object at 0x7f59388331d0>
------①這里是LoggerMixin的display函數-start--
--------②這里是Displayer.display函數---start-----
Displayer的self= <__main__.MySubClass object at 0x7f59388331d0>
This string will be shown and logged in subclasslog.txt
--------②這里是Displayer.display函數---end-----
MySubClass self= <__main__.MySubClass object at 0x7f59388331d0>
--------③這里是LoggerMixin.log函數---start-----
--------③這里是LoggerMixin.log函數---end-----
------①這里是LoggerMixin的display函數-end--
我們很直觀地可以看出:
如果沒有LoggerMixin,那么上述結果就會只剩下紅色部分,
當前實驗結果的黑色部分是對原有的Displayer的類的功能進行擴充.
同時又確保Displayer的類不被修改
#----------------總結------------------------
個人總結MIXIN的作用:
不修改父類的情況下,對父類的功能進行擴增和刪改
為什么沒有"査"呢?像數據庫那樣的增刪改查.
遺產項目中,同事給你的接口肯定是已經實現"查詢和獲取成員變量"的功能的,即使沒有MIXIN也已經具備了"査"功能.
擴增:上面兩個例子都體現了增加功能的作用
刪改:參考上面的案例一,WalkExMixin中的Walk函數屏蔽了原始父類Role的Walk函數
所以說,MIXIN這種設計模式出現的目的就是:
可以對原始父類實現功能上的擴增和(刪改).
#----------------------------------------
Reference:
[1]一個例子走近 Python 的 Mixin 類:利用 Python 多繼承的魔力
[2]面向對象-mixin設計模式的應用(多繼承應用場景)
[3]python_Mixin設計模式
總結
以上是生活随笔為你收集整理的Python中的Mixin详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: clickhouse 行列转换
- 下一篇: 5000以下固定资产怎么做账