您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Python中的鴨子類型和猴子補(bǔ)丁怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Python中的鴨子類型和猴子補(bǔ)丁怎么使用”吧!
引用維基百科中的一段解釋:
鴨子類型(duck typing)在程序設(shè)計(jì)中是動(dòng)態(tài)類型的一種風(fēng)格。在這種風(fēng)格中,一個(gè)對(duì)象有效的語(yǔ)義,不是由繼承自特定的類或?qū)崿F(xiàn)特定的接口,而是由"當(dāng)前方法和屬性的集合"決定。
更通俗一點(diǎn)的說:
當(dāng)看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子。
也就是說,在鴨子類型中,關(guān)注點(diǎn)在于對(duì)象的行為,能作什么;而不是關(guān)注對(duì)象所屬的類型。
我們看一個(gè)例子,更形象地展示一下:
# 這是一個(gè)鴨子(Duck)類 class Duck: def eat(self): print("A duck is eating...") def walk(self): print("A duck is walking...") # 這是一個(gè)狗(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 是一門動(dòng)態(tài)語(yǔ)言,沒有嚴(yán)格的類型檢查。只要 Duck 和 Dog 分別實(shí)現(xiàn)了 eat 和 walk 方法就可以直接調(diào)用。
再比如 list.extend() 方法,除了 list 之外,dict 和 tuple 也可以調(diào)用,只要它是可迭代的就都可以調(diào)用。
看過上例之后,應(yīng)該對(duì)「對(duì)象的行為」和「對(duì)象所屬的類型」有更深的體會(huì)了吧。
再擴(kuò)展一點(diǎn),其實(shí)鴨子類型和接口挺像的,只不過沒有顯式定義任何接口。
比如用 Go 語(yǔ)言來實(shí)現(xiàn)鴨子類型,代碼是這樣的:
package main import "fmt" // 定義接口,包含 Eat 方法 type Duck interface { Eat() } // 定義 Cat 結(jié)構(gòu)體,并實(shí)現(xiàn) Eat 方法 type Cat struct{} func (c *Cat) Eat() { fmt.Println("cat eat") } // 定義 Dog 結(jié)構(gòu)體,并實(shí)現(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() } }
通過顯式定義一個(gè) Duck 接口,每個(gè)結(jié)構(gòu)體實(shí)現(xiàn)接口中的方法來實(shí)現(xiàn)。
猴子補(bǔ)丁(Monkey Patch)的名聲不太好,因?yàn)樗鼤?huì)在運(yùn)行時(shí)動(dòng)態(tài)修改模塊、類或函數(shù),通常是添加功能或修正缺陷。
猴子補(bǔ)丁在內(nèi)存中發(fā)揮作用,不會(huì)修改源碼,因此只對(duì)當(dāng)前運(yùn)行的程序?qū)嵗行А?/p>
但如果濫用的話,會(huì)導(dǎo)致系統(tǒng)難以理解和維護(hù)。
主要有兩個(gè)問題:
補(bǔ)丁會(huì)破壞封裝,通常與目標(biāo)緊密耦合,因此很脆弱
打了補(bǔ)丁的兩個(gè)庫(kù)可能相互牽絆,因?yàn)榈诙€(gè)庫(kù)可能會(huì)撤銷第一個(gè)庫(kù)的補(bǔ)丁
所以,它被視為臨時(shí)的變通方案,不是集成代碼的推薦方式。
按照慣例,還是舉個(gè)例子來說明:
# 定義一個(gè)Dog類 class Dog: def eat(self): print("A dog is eating ...") # 在類的外部給 Dog 類添加猴子補(bǔ)丁 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 ...
這里相當(dāng)于在類的外部給 Dog 類增加了一個(gè) walk 方法,而調(diào)用方式與類的內(nèi)部定義的屬性和方法一樣。
再舉一個(gè)比較實(shí)用的例子,比如我們常用的 json 標(biāo)準(zhǔn)庫(kù),如果說想用性能更高的 ujson 代替的話,那勢(shì)必需要將每個(gè)文件的引入:
import json
改成:
import ujson as json
如果這樣改起來成本就比較高了。這個(gè)時(shí)候就可以考慮使用猴子補(bǔ)丁,只需要在程序入口加上:
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 方法的時(shí)候就是調(diào)用的 ujson 包,還是很方便的。
到此,相信大家對(duì)“Python中的鴨子類型和猴子補(bǔ)丁怎么使用”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。