Python 語言中的 “鴨子型別”

weixin_33912445發表於2018-11-05

提到 “鴨子型別”,就要先講講物件導向程式語言中的繼承和多型。

繼承

首先建立一個 Animal() 父類,父類繼承自 objectobject 是所有類都會繼承的類:

class Animal(object):
    
    def run(self):
        print("The animal is running...")

然後建立兩個子類,繼承自 Animal()

class Dog(Animal):
    pass

class Cat(Animal):
    pass

繼承的意思就是擁有所有父類的特性。這也是繼承的好處,實現了程式碼複用。所以,Dog()Cat() 均有了 run() 方法:

dog = Dog()
dog.run()

cat = Cat()
cat.run()
--------------
The animal is running...
The animal is running...

對上面兩個子類進行一些程式碼修改:

class Dog(Animal):

    def run(self):
        print('The dog is running...')

class Cat(Animal):

    def run(self):
        print('The cat is running...')

執行結果如下:

dog = Dog()
dog.run()

cat = Cat()
cat.run()
--------------
The dog is running...
The cat is running...

可以看到子類的 run() 方法覆蓋了父類的 run()方法。

多型

上面最後的執行結果,體現了多型的思想。即:動物裡面包含很多不同種類的動物,如:貓,狗,豬等等,但是它們有相同的特性就是跑,我們可以使用相同的方法來訪問它們。下面建立一個函式來體現多型:

class Animal(object):
    
    def run(self):
        print("The animal is running...")

class Dog(Animal):

    def run(self):
        print('The dog is running...')

class Cat(Animal):

    def run(self):
        print('The cat is running...')

def makeRun(animalType):
    animalType.run()


dog = Dog()
cat = Cat()
makeRun(dog)
makeRun(cat)

輸出結果為:

The dog is running...
The cat is running...

鴨子型別

在程式設計中,鴨子型別(英語:duck typing)是動態型別的一種風格。在這種風格中,一個物件有效的語義,不是由繼承自特定的類或實現特定的介面,而是由"當前方法"方法 (電腦科學)")和屬性的集合"決定。這個概念的名字來源於由James Whitcomb Riley提出的鴨子測試,“鴨子測試”可以這樣表述:“當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就可以被稱為鴨子。” 在鴨子型別中,關注點在於物件的行為,能作什麼;而不是關注物件所屬的型別。-- 摘自鴨子型別的維基百科

對於上面的 makeRun() 函式來說,傳入的引數並不一定需要是 Animal 型別的,只需要保證傳入的物件有一個 run() 方法即可,如下面程式碼所示。這就是動態語言的“鴨子型別”,它並不要求嚴格的繼承體系,一個物件只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子。

class Person(object):
    def run(self):
        print("The person is running...")

person = Person()
makeRun(person)
----------------------------
The person is running...

而在靜態語言中,如 Java ,如果需要傳入 Animal 型別,則傳入的物件就必須是 Animal 型別或者它的子類,否則,將無法呼叫 run() 方法。

參考

[1]. 繼承和多型 - 廖雪峰的官方網站
[2]. Polymorphism - Python Tutorials

相關文章