Python作為一門動態語言,其變數的型別可以自由變化。這個特性提高了程式碼的開發效率,卻也增加了閱讀程式碼和維護程式碼的難度。
假設有一個變數is_request_finished
,從名字上來看,這個變數的值應該為True
或者False
,在寫程式碼的時候,最初也確實是這樣定義的。但是可能由於某些原因,在某一次賦值的時候,is_request_finished = 'True'
。此時,如果程式碼的單元測試不夠完善,那麼if is_request_finished
在 is_request_finished = True
和 is_request_finished = 'True'
的時候都成立,問題被隱藏了。但是當is_request_finished = 'False'
的時候,由於'False'
作為一個非空字串,就會使得if is_request_finished
依然成立,從而使程式的行為發現異常。
單個變數的型別異常也許還容易發現,但是如果變數是放在字典或者列表裡面,那就比較麻煩了。假設需要儲存一段個人資訊,於是建立了下面這樣一個列表套字典的資料結構:
person_list = [{
'name': 'kingname',
'age': 23,
'sex': 'male'
'detail': {
'address': 'xxx',
'work': 'engineer',
'salary': 100000
}
},
{
'name': 'xiaoming',
'age': 65,
'sex': 'male'
'detail': {
'address': 'yyy',
'work': 'pm',
'salary': 0.5
}
}]複製程式碼
這種方式開發起來非常的快速而方便,但是其他人甚至是開發者自己在一段時間以後讀程式碼,都會有一種想抽死自己的衝動。因為根本不知道這個變數裡面儲存的是什麼東西。
針對以上問題,常見的解決辦法有三種。
Type Hints 與 Variable Annotations
在PEP 484中,引入了Type Hints,在PEP 526中引入了Variable Annotations。它使得Python 3.6及以後的Python 程式碼擁有了“宣告”變數型別的能力。這裡的“宣告”之所以會打引號,是因為這個宣告是給IDE和人看的。這個宣告對 Python 的直譯器無效。
Type Hints
PyCharm現在已經可以比較好地支援Type Hints了。例如下面這一段程式碼:
def upload(url):
print(f'now upload a file to {url}')
return True複製程式碼
模擬一段上傳檔案的函式,上傳成功以後返回True。接收一個引數url
。在正常情況下,這個url
應該是一個字串。於是,使用Type Hints,程式碼可以變為:
def upload(url: str) -> bool:
print(f'now upload a file to {url}')
return True複製程式碼
如果直接執行,其執行效果如下圖所示:
現在假設傳遞一個不是字串的變數給upload
函式,此時PyCharm就會提示型別有問題,如下圖所示:
但提示歸提示,強行執行也是沒有問題的。這就說明Type Hints主要是給IDE和人用的,直譯器並不會關心型別正不正確。
如果修改這個函式的返回值,讓它不返回True
或者False
,PyCharm 也會發出警告:
Type Hints的官方文件,可以參閱:typing — Support for type hints
Variable Annotations
對於Variable Annotations,如下圖所示,雖然目前PyCharm還不能很好地提示變數型別不對,但是人在讀程式碼的時候,還是會起到一定的幫助。
除了這種寫法外,Variable Annotations還支援把型別寫在註釋中,如下圖所示:
雖然PyCharm不能起到很好的提示作用,但是可以使用一個第三方庫mypy
來對程式碼做靜態檢查,其執行效果如下圖所示,可以發現賦值的型別與宣告的型別不一致(expression has type "str", variable has type "bool", 表示式的型別為“str”,變數的型別是“bool”)。
關於Variable Annotations的更多用法,可以參閱:Syntax for Variable Annotations
關於Mypy,可以參閱它的官方文件:Mypy documentation
docstring
在docstring來標註變數的型別,如下圖所示:
這種寫法可以用來提示一個函式,或者一個類它裡面的各個變數的情況。但是詳細程度需要看開發者有沒有耐心把這個註釋寫清楚。
Bean
這種方法來自與Java Bean的思想,它主要用來解決列表套字典,字典套字典,字典套列表,列表套列表這種深層的巢狀關係。關於這個方法,請參閱另一篇文章:可愛的豆子——使用Beans思想讓Python程式碼更易維護