簡單聊聊Python中的鴨子類型和猴子補丁
前言
Python 開發(fā)者可能都聽說過鴨子類型和猴子補丁這兩個詞,即使沒聽過,也大概率寫過相關(guān)的代碼,只不過并不了解其背后的技術(shù)要點是這兩個詞而已。
我最近在面試候選人的時候,也會問這兩個概念,很多人答的也并不是很好。但是當我向他們解釋完之后,普遍都會恍然大悟:“哦,是這個啊,我用過”。
所以,我決定來寫一篇文章,探討一下這兩個技術(shù)。
鴨子類型
引用維基百科中的一段解釋:
鴨子類型(duck typing)在程序設(shè)計中是動態(tài)類型的一種風格。在這種風格中,一個對象有效的語義,不是由繼承自特定的類或?qū)崿F(xiàn)特定的接口,而是由"當前方法和屬性的集合"決定。
更通俗一點的說:
當看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子。
也就是說,在鴨子類型中,關(guān)注點在于對象的行為,能作什么;而不是關(guān)注對象所屬的類型。
我們看一個例子,更形象地展示一下:
# 這是一個鴨子(Duck)類 class Duck: ? ? def eat(self): ? ? ? ? print("A duck is eating...") ? ? def walk(self): ? ? ? ? print("A duck is walking...") # 這是一個狗(Dog)類 class Dog: ? ? def eat(self): ? ? ? ? print("A dog is eating...") ? ? def walk(self): ? ? ? ? print("A dog is walking...") def animal(obj): ? ? obj.eat() ? ? obj.walk() if __name__ == '__main__': ? ? animal(Duck()) ? ? animal(Dog())
程序輸出:
A duck is eating...
A duck is walking...
A dog is eating...
A dog is walking...
Python 是一門動態(tài)語言,沒有嚴格的類型檢查。只要 Duck 和 Dog 分別實現(xiàn)了 eat 和 walk 方法就可以直接調(diào)用。
再比如 list.extend() 方法,除了 list 之外,dict 和 tuple 也可以調(diào)用,只要它是可迭代的就都可以調(diào)用。
看過上例之后,應(yīng)該對「對象的行為」和「對象所屬的類型」有更深的體會了吧。
再擴展一點,其實鴨子類型和接口挺像的,只不過沒有顯式定義任何接口。
比如用 Go 語言來實現(xiàn)鴨子類型,代碼是這樣的:
package main import "fmt" // 定義接口,包含 Eat 方法 type Duck interface { ?Eat() } // 定義 Cat 結(jié)構(gòu)體,并實現(xiàn) Eat 方法 type Cat struct{} func (c *Cat) Eat() { ?fmt.Println("cat eat") } // 定義 Dog 結(jié)構(gòu)體,并實現(xiàn) Eat 方法 type Dog struct{} func (d *Dog) Eat() { ?fmt.Println("dog eat") } func main() { ?var c Duck = &Cat{} ?c.Eat() ?var d Duck = &Dog{} ?d.Eat() ?s := []Duck{ ? &Cat{}, ? &Dog{}, ?} ?for _, n := range s { ? n.Eat() ?} }
通過顯式定義一個 Duck 接口,每個結(jié)構(gòu)體實現(xiàn)接口中的方法來實現(xiàn)。
猴子補丁
猴子補丁(Monkey Patch)的名聲不太好,因為它會在運行時動態(tài)修改模塊、類或函數(shù),通常是添加功能或修正缺陷。
猴子補丁在內(nèi)存中發(fā)揮作用,不會修改源碼,因此只對當前運行的程序?qū)嵗行А?/p>
但如果濫用的話,會導致系統(tǒng)難以理解和維護。
主要有兩個問題:
- 補丁會破壞封裝,通常與目標緊密耦合,因此很脆弱
- 打了補丁的兩個庫可能相互牽絆,因為第二個庫可能會撤銷第一個庫的補丁
所以,它被視為臨時的變通方案,不是集成代碼的推薦方式。
按照慣例,還是舉個例子來說明:
# 定義一個Dog類 class Dog: ? ? def eat(self): ? ? ? ? print("A dog is eating ...") # 在類的外部給 Dog 類添加猴子補丁 def walk(self): ? ? print("A dog is walking ...") Dog.walk = walk # 調(diào)用方式與類的內(nèi)部定義的屬性和方法一樣 dog = Dog() dog.eat() dog.walk()
程序輸出:
A dog is eating ...
A dog is walking ...
這里相當于在類的外部給 Dog 類增加了一個 walk 方法,而調(diào)用方式與類的內(nèi)部定義的屬性和方法一樣。
再舉一個比較實用的例子,比如我們常用的 json 標準庫,如果說想用性能更高的 ujson 代替的話,那勢必需要將每個文件的引入:
import json
改成:
import ujson as json
如果這樣改起來成本就比較高了。這個時候就可以考慮使用猴子補丁,只需要在程序入口加上:
import json ? import ujson ? def monkey_patch_json(): ? ? ? json.__name__ = 'ujson' ? ? ? json.dumps = ujson.dumps ? ? ? json.loads = ujson.loads ? monkey_patch_json()
這樣在以后調(diào)用 dumps 和 loads 方法的時候就是調(diào)用的 ujson 包,還是很方便的。
但猴子補丁就是一把雙刃劍,問題也在上文中提到了,看需,謹慎使用吧。
總結(jié)
到此這篇關(guān)于Python中鴨子類型和猴子補丁的文章就介紹到這了,更多相關(guān)Python鴨子類型和猴子補丁內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python利用format函數(shù)實現(xiàn)對齊打印(左對齊、右對齊與居中對齊)
format是字符串內(nèi)嵌的一個方法,用于格式化字符串,下面這篇文章主要給大家介紹了關(guān)于Python利用format函數(shù)實現(xiàn)對齊打印(左對齊、右對齊與居中對齊)的相關(guān)資料,需要的朋友可以參考下2022-04-04python使用tkinter實現(xiàn)自定義多參數(shù)對話框
Tkinter模塊是Python標準庫中的一部分,用于創(chuàng)建圖形用戶界面(GUI)應(yīng)用程序,它提供了一組工具和組件,用于創(chuàng)建窗口、按鈕、文本框等用戶界面元素,并且可以響應(yīng)用戶的輸入,本文將給大家講講python如何使用tkinter實現(xiàn)自定義多參數(shù)對話框2023-08-08Python?NLP開發(fā)之實現(xiàn)聊天機器人
這篇文章主要為大家介紹了Python如何實現(xiàn)聊天機器人,即使用自然語言處理?(NLP)?來幫助用戶通過文本、圖形或語音與?Web?服務(wù)或應(yīng)用進行交互,感興趣的可以了解一下2023-05-05你知道怎么改進Python 二分法和牛頓迭代法求算術(shù)平方根嗎
這篇文章主要介紹了Python編程實現(xiàn)二分法和牛頓迭代法求平方根代碼的改進,具有一定參考價值,需要的朋友可以了解下,希望能夠給你帶來幫助2021-08-08python3實現(xiàn)往mysql中插入datetime類型的數(shù)據(jù)
這篇文章主要介紹了python3實現(xiàn)往mysql中插入datetime類型的數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03pyppeteer執(zhí)行js繞過webdriver監(jiān)測方法上
這篇文章主要為大家介紹了pyppeteer執(zhí)行js繞過webdriver監(jiān)測方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04在ipython notebook中使用argparse方式
這篇文章主要介紹了在ipython notebook中使用argparse方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04python如何實現(xiàn)不可變字典inmutabledict
這篇文章主要介紹了python如何實現(xiàn)不可變字典inmutabledict,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-01-01python爬蟲 基于requests模塊發(fā)起ajax的get請求實現(xiàn)解析
這篇文章主要介紹了python爬蟲 基于requests模塊發(fā)起ajax的get請求實現(xiàn)解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-08-08