動態語言與鴨子型別

劉志軍發表於2017-09-05

今天來說說程式語言中的動態型別語言與鴨子型別,維基百科對動態語言的定義:

動態程式語言是一類在執行時可以改變其結構的語言:例如新的函式、物件、甚至程式碼可以被引進,已有的函式可以被刪除或是其他結構上的變化。動態語言目前非常具有活力如PHP、Ruby、Python 都屬於動態語言,而C、C++、Java等語言則不屬於動態語言。

這個解釋很抽象,其實動態語言是相對靜態語言而言的,靜態語言的特點是在程式執行前,程式碼編譯時從程式碼中就可以知道一切,比如變數的型別,方法的返回值型別:

String s = "hello"
s = "world"
s = 1 // 編譯時就會報錯複製程式碼

在靜態語言中,變數有型別資訊,它是一塊記憶體區域,靜態語言的優點是程式碼結構非常規範,便於除錯,但有時顯得囉嗦。而動態語言只有等到程式執行時才知道一切,變數(嚴格來說叫名字,就像人的名字一樣)不需要指定型別,變數本身沒有任何型別資訊,型別資訊在物件身上,物件是什麼型別,必須等到程式執行時才知道,動態型別語言的優點在於方便閱讀,不需要寫很多型別相關的程式碼;缺點是不方便除錯,命名不規範時會造成讀不懂,不利於理解等。

s = "hello"
s = "world"
s = 1  # 可以給變數隨意賦值,無論是什麼型別都可以複製程式碼

鴨子型別

動態語言中經常提到鴨子型別,所謂鴨子型別就是:如果走起路來像鴨子,叫起來也像鴨子,那麼它就是鴨子(If it walks like a duck and quacks like a duck, it must be a duck)。鴨子型別是程式語言中動態型別語言中的一種設計風格,一個物件的特徵不是由父類決定,而是通過物件的方法決定的。

如果你學的是Java或者C++等靜態語言,可能對鴨子型別的理解沒那麼深刻,因為靜態語言中物件的特性取決於其父類。而動態語言則不一樣,比如迭代器,任何實現了 __iter____next__方法的物件都可稱之為迭代器,但物件本身是什麼型別不受限制,可以自定義為任何類

# python3
class Foo:
    def __iter__(self):
        pass

    def __next__(self):
        pass

from collections import Iterable
from collections import Iterator

print(isinstance(Foo(), Iterable)) # True
print(isinstance(Foo(), Iterator)) # True複製程式碼

我們並不需要繼承 Iterator 就可以實現迭代器的功能。當有一函式希望接收的引數是 Iterator 型別時,但是我們傳遞的是 Foo 的例項物件,其實也沒問題,換成是Java等靜態語言,就必須傳遞 Iterator或者是它的子類。鴨子型別通常得益於"不"測試方法和函式中引數的型別,而是依賴文件、清晰的程式碼和測試來確保正確使用,這既是優點也是缺點,缺點是需要通過文件才能知道引數型別,為了彌補這方面的不足,Python3.6引入了型別資訊,定義變數的時候可以指定型別,例如:

def greeting(name: str) -> str:
    return 'Hello ' + name複製程式碼

該函式表示接收str型別的引數,並返回str型別的值

python之禪
python之禪

相關文章