動態型別一時爽,程式碼重構火葬場?
題圖: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也能提示我們寫得不對:
除了 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)
本文可接受反駁
推薦閱讀
關注這個公眾號的
最後都學會了程式設計
相關文章
- 如何用程式碼動態生成ABAP型別型別
- .NET重構(型別碼的設計、重構方法)型別
- 淺談程式語言型別的強型別,弱型別,動態型別,靜態型別型別
- RAC重構型別型別
- 拖延一時爽,精神狀態火葬場……大學生資料表明,拖延行為與之後9個月抑鬱、焦慮、致殘性疼痛等不良健康結果有關
- 【Java】程式碼重構時,為什麼禁止在方法內對物件型別的入參賦值Java物件型別賦值
- 重複程式碼(克隆程式碼)的幾個概念與型別型別
- C# 4.0中的動態型別和動態程式設計C#型別程式設計
- 程式碼重構--大話重構
- 記一次程式碼重構
- 程式碼重構
- 程式碼重構之法——方法重構分析
- 重構遺留程式碼(7):識別表示層
- “硬核”程式碼重構
- 重構 PHP 程式碼PHP
- PHP程式碼重構PHP
- 程式碼重構(四)
- 動態圖和靜態圖的程式碼區別
- 程式碼重構與單元測試(一)
- BGP報文結構&型別、狀態型別
- C# 中的動態型別C#型別
- 動態語言與鴨子型別型別
- C的動態型別檢查型別
- C++ 動態型別轉換C++型別
- 為什麼動態型別程式語言會如此流行?型別
- 程式碼重構技巧(二)
- 談談程式碼重構
- 【讀程式碼重構有感】
- 重構:程式碼異味
- Mac Jenkins 構建 Android App 時動態設定程式碼引數MacJenkinsAndroidAPP
- 程式碼重構與單元測試——重構6:使用“多型”取代條件表示式(九)多型
- leobert重構程式碼二三事--一.可怕的低階程式碼
- 基礎程式碼重構的若干建議(一)
- 程式碼重構:類重構的 8 個小技巧
- .NET重構—單元測試的程式碼重構
- 11.9 上下爽一爽
- js判斷移動端型別或者瀏覽器型別程式碼例項JS型別瀏覽器
- 重溫手冊(一):資料型別資料型別