Python的鴨子類型

‘那只東西呱呱的叫,有扁扁的嘴巴勃救,走起路來(lái)還外八碍讨,對(duì)!它就是只鴨子’

  1. 基本定義
    對(duì)于熟悉python的開(kāi)發(fā)者來(lái)說(shuō)蒙秒,相信對(duì)于python的鴨子類型比較熟悉勃黍,所謂鴨子類型,在維基百科中的準(zhǔn)確定義是‘是動(dòng)態(tài)類型的一種風(fēng)格晕讲。在這種風(fēng)格中覆获,一個(gè)對(duì)象有效的語(yǔ)義,不是由繼承自特定的類或?qū)崿F(xiàn)特定的接口瓢省,而是由"當(dāng)前方法和屬性的集合"決定’弄息。

  2. python中的具體實(shí)現(xiàn)
    下面的代碼就是一個(gè)簡(jiǎn)單的鴨子類型

class duck():
    def walk(self):
        print('I walk like a duck')
    def swim(self):
        print('i swim like a duck')

class person():
    def walk(self):
        print('this one walk like a duck') 
    def swim(self):
        print('this man swim like a duck')

對(duì)于一個(gè)鴨子類型來(lái)說(shuō),我們并不關(guān)心這個(gè)對(duì)象的類型本身或是這個(gè)類繼承勤婚,而是這個(gè)類是如何被使用的摹量。我們可以通過(guò)下面的代碼來(lái)調(diào)用這些類的方法。

def watch_duck(animal):
    animal.walk()
    animal.swim()

small_duck = duck()
watch_duck(small_duck)

output >> 
I walk like a duck
i swim like a duck


duck_like_man = person()
watch_duck(duck_like_man)

output >> 
this one walk like a duck
this man swim like a duck


class Lame_Foot_Duck():
    def swim(self):
        print('i am lame but i can swim')

lame_duck = Lame_Foot_Duck()
watch_duck(lame_duck)

output >>
AttributeError: Lame_Foot_Duck instance has no attribute 'walk'

watch_duck函數(shù)接收這個(gè)類的對(duì)象蛔六,然后并沒(méi)有檢查對(duì)象的類型荆永,而是直接調(diào)用這個(gè)對(duì)象的走和游的方法,如果所需要的方法不存在就報(bào)錯(cuò)国章。具體在python中鴨子類型的體現(xiàn)如下面的代碼所示

class CollectionClass():
    lists = [1,2,3,4]
    def __getitem__(self, index):
        return self.lists[index]

iter_able_object = CollectionClass()

class Another_iterAbleClass():
    lists=[1,2,3,4]
    list_position = -1

    def __iter__(self):
        return self

    def next(self): #還有更簡(jiǎn)單的實(shí)現(xiàn)具钥,使用生成器或迭代器什么的:)
        self.list_position += 1
        if self.list_position >3:
            raise StopIteration
        return self.lists[self.list_position]

another_iterable_object=Another_iterAbleClass()

print(iter_able_object[1])
print(iter_able_object[1:3])
output>>
2
[2, 3]

another_iterable_object[2]
output>>
Traceback (most recent call last):
  File "/Users/steinliber/a.py", line 32, in <module>
    another_iterable_object[2]
TypeError: 'Another_iterAbleClass' object does not support indexing

print(next(another_iterable_object))
output>>
1
print(next(another_iterable_object))
output>>
2

print(next(iter_able_object))
output>>
Traceback (most recent call last):
  File "/Users/steinliber/a.py", line 29, in <module>
    print(next(iter_able_object))
TypeError: IterAbleClass object is not an iterator

在python把上述代碼的實(shí)現(xiàn)方法叫做protocol(協(xié)議),這些protocol可以看作是通知型的接口液兽,它規(guī)定了調(diào)用方使用該功能要調(diào)用對(duì)象的哪些方法骂删,被調(diào)用方要實(shí)現(xiàn)哪些方法才能完成這個(gè)功能掌动。它和java中的接口區(qū)別在于java中的接口功能實(shí)現(xiàn)需要通過(guò)繼承,繼承的類必須實(shí)現(xiàn)接口中的所有的抽象方法宁玫,所以在Java中強(qiáng)調(diào)的是類型的概念粗恢,而python中的protocol更多的是通知性的,一個(gè)函數(shù)規(guī)定要實(shí)現(xiàn)某個(gè)功能需要調(diào)用傳入對(duì)象的哪些方法欧瘪,所有實(shí)現(xiàn)這些方法的類就可以實(shí)現(xiàn)這個(gè)功能眷射。

具體從上面兩個(gè)類來(lái)說(shuō),第一個(gè)類實(shí)現(xiàn)了__getitem__方法,那python的解釋器就會(huì)把它當(dāng)做一個(gè)collection佛掖,就可以在這個(gè)類的對(duì)象上使用切片,獲取子項(xiàng)等方法妖碉,第二個(gè)類實(shí)現(xiàn)了__iter__和next方法,python就會(huì)認(rèn)為它是一個(gè)iterator芥被,就可以在這個(gè)類的對(duì)象上通過(guò)循環(huán)來(lái)獲取各個(gè)子項(xiàng)欧宜。一個(gè)類可以實(shí)現(xiàn)它有能力實(shí)現(xiàn)的方法,并只能被用于在它有意義的情況下拴魄。

這兩個(gè)類和上面的鴨子類相比較冗茸,其實(shí)用于切邊的[](它其實(shí)調(diào)用的是python的slice函數(shù))和用于循環(huán)的iter()就相當(dāng)于watch_duck函數(shù),這些函數(shù)都接收任意類的對(duì)象匹中,并調(diào)用實(shí)現(xiàn)功能所需要的對(duì)象中的方法來(lái)實(shí)現(xiàn)功能夏漱,若該函數(shù)中調(diào)用的方法對(duì)象里面不存在,就報(bào)錯(cuò)顶捷。

從上面可以看出麻蹋,python鴨子類型的靈活性在于它關(guān)注的是這個(gè)所調(diào)用的對(duì)象是如何被使用的,而沒(méi)有關(guān)注對(duì)象類型的本身是什么焊切。所以在python中使用isinstance來(lái)判斷傳入?yún)?shù)的類型是不提倡的,更pythonic的方法是直接使用傳入的參數(shù)芳室,通過(guò)try专肪,except來(lái)處理傳入?yún)?shù)不符合要求的情況。我們應(yīng)該通過(guò)傳入對(duì)象的能力而不是傳入對(duì)象的類型來(lái)使用該對(duì)象堪侯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嚎尤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子伍宦,更是在濱河造成了極大的恐慌芽死,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件次洼,死亡現(xiàn)場(chǎng)離奇詭異关贵,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)卖毁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)揖曾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事炭剪×妨矗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵奴拦,是天一觀的道長(zhǎng)媒鼓。 經(jīng)常有香客問(wèn)我,道長(zhǎng)错妖,這世上最難降的妖魔是什么绿鸣? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮站玄,結(jié)果婚禮上枚驻,老公的妹妹穿的比我還像新娘。我一直安慰自己株旷,他們只是感情好再登,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著晾剖,像睡著了一般锉矢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上齿尽,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天沽损,我揣著相機(jī)與錄音,去河邊找鬼循头。 笑死绵估,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卡骂。 我是一名探鬼主播国裳,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼全跨!你這毒婦竟也來(lái)了缝左?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤浓若,失蹤者是張志新(化名)和其女友劉穎渺杉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體挪钓,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡是越,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了碌上。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片英妓。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡挽放,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蔓纠,到底是詐尸還是另有隱情辑畦,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布腿倚,位于F島的核電站纯出,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏敷燎。R本人自食惡果不足惜暂筝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望硬贯。 院中可真熱鬧焕襟,春花似錦、人聲如沸饭豹。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拄衰。三九已至它褪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間翘悉,已是汗流浹背茫打。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妖混,地道東北人老赤。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像制市,于是被迫代替她去往敵國(guó)和親诗越。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 要點(diǎn): 函數(shù)式編程:注意不是“函數(shù)編程”息堂,多了一個(gè)“式” 模塊:如何使用模塊 面向?qū)ο缶幊蹋好嫦驅(qū)ο蟮母拍睢傩浴?..
    victorsungo閱讀 1,509評(píng)論 0 6
  • # 第一優(yōu)先級(jí)規(guī)則聲明: # 除了夢(mèng)境块促,每一個(gè)意識(shí)主進(jìn)程都必須與一個(gè)身體參與的機(jī)械進(jìn)程相匹配荣堰,否則結(jié)束意識(shí)主進(jìn)程。...
    李洞BarryLi閱讀 3,861評(píng)論 0 1
  • Python進(jìn)階框架 希望大家喜歡竭翠,點(diǎn)贊哦首先感謝廖雪峰老師對(duì)于該課程的講解 一振坚、函數(shù)式編程 1.1 函數(shù)式編程簡(jiǎn)...
    Gaolex閱讀 5,498評(píng)論 6 53
  • http://blog.csdn.net/nugongahou110/article/details/481548...
    Mr_468閱讀 478評(píng)論 0 0
  • 活著就該有活著的價(jià)值 你的判斷太過(guò)于草率 許多事情并不能按照直覺(jué)來(lái) 不要被小的利益吸引 堅(jiān)持很重要,穩(wěn)定的心境是堅(jiān)...
    nazarite閱讀 192評(píng)論 0 0