你知道什么是Python里的鴨子類型和猴子補丁嗎?
有時候我們會聽到Python里所謂的鴨子類型和猴子補丁的說法,乍一聽還以為是來到了動物園,Python這只大蟒蛇還可以和鴨子和猴子一起玩耍?


非也非也,鴨子類型和猴子補丁實際上是兩個生動有趣的比喻,用來說明Python的動態(tài)特性。
鴨子類型?(duck type) 是對Python中數(shù)據(jù)類型本質(zhì)上是由屬性和行為來定義的一種解讀。
猴子補丁?(monkey patching)是對Python中類和模塊可以在外部被動態(tài)修改這種特性的一個比喻。
讓我們來一探究竟吧!
一,鴨子類型
鴨子類型是對Python中數(shù)據(jù)類型本質(zhì)上是由屬性和行為來定義的一種解讀。
Python是一種動態(tài)語言,不像Java和C++這種強類型語言,Python里實際上沒有嚴格的類型檢查。
只要某個對象具有鴨子的方法,可以像鴨子那樣走路和嘎嘎叫,那么它就可以被其它函數(shù)當做鴨子一樣調(diào)用。
#?這是一個鴨子(Duck)類
class?Duck:
????def?__init__(self,name):
????????self.name?=?name
????def?swim(self):
????????print("A?duck?named?"?+?self.name+"?is?swimming...")
????def?call(self):
????????print("gay...gay...gay...")
#?這是一個鵝(Goose)類
class?Goose:
????def?__init__(self,name):
????????self.name?=?name
????def?swim(self):
????????print("A?goose?named?"?+?self.name+"?is?swimming...")
????def?call(self):
????????print("goo...goo...goo...")
# duckshow這個函數(shù)設(shè)計的本意是需要傳入一個Duck對象作為參數(shù)的。?
def?duckshow(duck):
????duck.swim()
????duck.call()
yaya?=?Duck("yaya")
ee?=?Goose("ee")
#?但由于Python是動態(tài)語言,其數(shù)據(jù)類型屬于鴨子類型,沒有嚴格類型檢查,
#?Goose這個類具有和Duck這個類相同的方法,
#?ee這只鵝劃起水來像只鴨子,叫起來也像一只鴨子,
#?所以duckshow這個函數(shù)也可以對ee進行作用。
duckshow(yaya)
duckshow(ee)
輸出結(jié)果如下:
A duck named yaya is swimming...gay ... gay ... gay ...A goose named ee is swimming...goo ... goo ... goo ...
二,猴子補丁
猴子補丁是對Python中模塊和類可以在外部被動態(tài)修改這種特性的一個比喻。
為什么叫做猴子補丁呢?在模塊和類的外部對模塊和類進行修改是一種非常耍賴的做法,會破壞代碼的封裝結(jié)構(gòu),這種事情大概只有淘氣的猴子喜歡去做,因此形象地稱之為猴子補丁。
#?定義一個Dog類
class?Dog:
????def?__init__(self,name,age):
????????self.name?=?name
????????self.age?=?age
????def?sleep(self):
????????print("Zzz...Zzz..Zzz...")
#?在類的外部給Dog這個類添加猴子補丁
def?speak(self):
????print("I?think?myself?a?hero?and?very?handsome!")
Dog.speak?=?speak
Dog.home?=?"Earth"
#?與類的內(nèi)部定義的屬性和方法無差異
snoopy?=?Dog("snoopy",3)
snoopy.sleep()
snoopy.speak()
print(snoopy.home)
輸出結(jié)果如下:
Zzz?...?Zzz?...?Zzz?...I think myself a hero and very handsome!Earth
對于庫中已經(jīng)定義好的類,給它們添加猴子補丁有時候會非常方便,相當于可以自由地在外面做擴展,又不用修改源文件。
import?numpy?as?np
import?pandas?as?pd
df?=?pd.DataFrame(np.random.randint(1,10,size=(5,5)),
??????????????????columns?=?list("abcde"))
#df.info()
#DataFrame自帶方法info打印信息太多,展示不直觀。
#給DataFrame定義一個猴子補丁方法memory簡潔展示其內(nèi)存消耗。
def?memory(self):
????mem?=?self.__sizeof__()
????if?mem<1024:
????????return("%s?B"%mem)
????elif?mem<1024*1024:
????????return("%s?KB"%mem/1024)
????elif?mem<1024**3:
????????return("%s?MB"%mem/1024**2)
????else:
????????return("%s?GB"%mem/1024**3)?
pd.DataFrame.memory?=?memory
print(df.memory())
輸出結(jié)果如下:
280 B這就是Python里的鴨子類型和猴子補丁的一個簡單介紹,你耍明白了嗎???????
評論
圖片
表情
