動態型別一時爽,程式碼重構火葬場?

Python之禪發表於2018-11-07

640?wx_fmt=jpeg
題圖:Photo by Timo Wagner on Unsplash

江湖有言:“動態型別一時爽,程式碼重構火葬場”,聽起來有點聳人聽聞,但也沒有想象中的那麼嚴重,因為 Python 在大型專案的應用實在太多。Python作為動態語言,程式碼簡潔、靈活,拋開執行效率不說,但存在的一些問題也是事實,例如:

1、IDE的智慧提示比較雞肋,舉個例子,字串有個 startswith 方法,你很容易忽略中間那個“s”,如果麼有 IDE 的幫助,不得不去查個文件。(其實現在的PyCharm 已經非常智慧了,即使沒有型別宣告。)

2、大部分錯誤只有在程式執行的時候才能被發現,編譯過程中只能發現簡單的語法錯誤。

3、介面呼叫全靠文件註釋說明,雖然我們可以使用 docstring,但是程式碼更新之後,你的 docstring 可能就沒有同步更新。

這些問題在大型專案,特別是多人合作的專案上顯得更為突出。所以遵循程式碼規範、Code Review 就變得尤為重要,如果能從語法層面上去規範程式碼無疑是最省成本的,所以在 Python3.5,也就是 PEP484 中就有了型別提示(Type Hints)。定義函式時,可以你指定函式的返回值型別、引數的型別。

以前定義一個函式可以接收任何型別的資料:

def greeting(name):
   return "Hello" + name

greeting("bob")
greeting(1)

程式執行前,不會有任何錯誤提示,雖然我們知道字串和數字是不支援“+”操作的。

在 Python3.5 中,用 Type Hint  寫法是這樣的:

def greeting(name: str) -> str:
   return 'Hello ' + name

上面就是靜態型別的寫法,多了 「: str」與 「-> str」,前者用來說明 name 的型別,後者指函式返回值的型別,我們在寫程式碼的過程中IDE也能提示我們寫得不對:

640?wx_fmt=png


除了 IDE 之外,我們還有更強大的靜態型別檢查工具,叫 mypy,這個工具也是由 Python 之父 Guido 親自操刀實現的靜態型別檢查工具。

# 先安裝mypy
pip install mypy

$ mypy test.py
test.py:4: error: Argument 1 to "greeting"
has incompatible type "int"; expected "str"

有了型別提示,Python在程式碼呼叫、重構、甚至是靜態分析等方面有了更好的效果,不但減輕了開發時自行進行型態檢查的負擔,更重要的是,由於有了型態上的提示,讓過去 Python 整合開發工具上做不好的各種智慧提示、重構等功能有了統一的參考標準。

某種意義上型別提示只是一種輔助功能,雖然我們加了資料型別提示,但是對於 Python 直譯器來說,它會直接忽略掉型別提示資訊,哪怕型別有誤也不會阻止程式的執行。

而對於變數的型別宣告,在 PEP484 中可以通過型別註釋來說明,就是以註釋的方式來說明變數的型別,例如:

from typing import List

x = []                # type: List[Employee]
y = [1, 2]            # type: List[int]
y.append("a")

在 Python3.6,也就是 PEP526 的提案中,針對變數註解做了進一步優化,將型別的宣告作為了語法的一部分,這樣比起註釋可讀性更強,例如:

my_var: int  # 宣告為整數型別的變數
my_var = 5  # 通過型別檢查
other_var: int = 'a'  # 給整數型別變數賦值字串,檢查器會報錯,但是直譯器執行是不會有任何問題
print(other_var)

執行mypy

mypy xx.py  # 執行型別檢查器
xx.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int")

python test.py # 執行直譯器

擁有了強大的型別提示之後,你還敢說重構程式碼是火葬場嗎?不過我反倒覺得動態語言變得越來越臃腫起來,例如:

T = TypeVar('T')
S = TypeVar('S')
class Foo(Generic[T]):
   def method(self, x: T, y: S) -> S:
   # Body

這讓一門原本簡潔優雅的語言跟Java一樣臃腫了,好在型別提示在Python中只是一種可選操作,而且對直譯器來說完全是不可見的。而且這種寫法也不是Python 的主流做法,大家可以去看看主流框架的原始碼,很少用這種特性。

雖然 Java 是一門很成功的語言(而且也開始加入動態型別等特性),但我更喜歡 Python 的理由是它給了開發者最大的自由。至於說程式碼好不好維護,真的跟人有關,畢竟大家都是成年人!( We are all consenting adults)

本文可接受反駁


推薦閱讀


640?
關注這個公眾號的
最後都學會了程式設計

相關文章