引入
我們在閱讀python3寫的代碼時,會看到類似如下的程序:
def add(x: int, y: int) -> int:
return x+y
初步看上去,與python2相比,這個函數在定義上,多了3個int。前兩個int表示輸入數據的類型,"->"符號後面的int,表示返回值類型。
在python中,是不用強制申明變量類型的。python3的這種新語法,貌似可以直接申明變量類型?
函數註解
- 函數註解的說明
這種“申明函數參數中變量類型,與返回值類型”的語法,就是python3所謂的“函數註解”[1]。
註解,只是“adding arbitrary metadata annotations to Python functions”,添加的這些“類型申明”,都是額外信息,不是強制要求的。
並且,“函數註解”的目的,是給人看的,不是給解釋器看。所以,哪怕類型使用錯誤,編譯器也不會報錯,舉例如下:
def add(x: int, y: int) -> int:
return x+y
z = add(3.14, 1.23)
用python3.0以上的版本運行這段程序,並不會報錯,即便實參是浮點型,而形參要求是整型。最終z的值是4.37。
Python 解釋器並不會因爲這些註解而提供額外的校驗,沒有任何的類型檢查工作。也就是說,這些類型註解加不加,對你的代碼來說沒有任何影響[2]。
“函數註解”的作用,僅僅是:(1)方便程序員查看,(2)IDE的設計者可以用來做代碼檢查。
- 如何訪問函數註解
我們如何得到某一個函數的類型註解呢?其實很簡單,使用__annotations__
就可以,比如上面定義的函數add
,運行如下代碼:
add.__annotations__
得到的結果就是{'return': int, 'x': int, 'y': int}
。
結果中能得到返回值與各個參數的類型要求。
變量註解
變量註解,就是“adding syntax to Python for annotating the types of variables (including class variables and instance variables)”,簡單來說就是爲變量(包括類中的變量與實例變量)添加類型註解。具體用法如下,注意要用python3.6以上的版本運行:
- int/str/float變量註解
a1: int # a1爲int型變量,沒有賦值
a2: int = 123 # a2爲int型變量,賦值爲123
b1: str # b1爲str型變量,沒有賦值
b2: str = 'hello'# b2爲str型變量,賦值爲hello
c1: float# c1爲float型變量,沒有賦值
c1: float = 3.14# c1爲float型變量,賦值爲3.14
注意,python的解釋器並不會爲變量進行真實的“類型檢查”,這種註解的作用只是爲了方便閱讀(或IDE自己來檢查),所以如下程序執行是正確的,不會報錯:
a1: int
a2: int = 123
a1 = 3.14
a2 = 'hello'
- list/tuple/dict變量註解
from typing import List, Tuple, Dict
a1: List[int] # a1是一個list,其中的數據都是int類型,沒有賦值
a2: List[str] = ['1','2','3']# a2是一個list,其中的數據都是int類型,賦值爲['1','2','3']
b1: Tuple[int] # a1是一個tuple,其中的數據都是int類型,沒有賦值
b2: Tuple[float] = (1.1,2.2,3.3)# a2是一個tuple,其中的數據都是float類型,賦值爲[1.1,2.2,3.3]
c1: [Dict[str, int]] = {} # c1是一個dict,其中key爲str類型,value爲int型,沒有賦值
c2: [Dict[str, int]] = {'a':1, 'b':2, 'c':3} # c1是一個dict,其中key爲str類型,value爲int型,賦值爲{'a':1, 'b':2, 'c':3}
同理,不按註解的類型來,也不會報錯。
- 如何訪問變量註解
在程序中申明的所有註解變量,都可以由__annotations__
來訪問到,如下:
>>> __annotations__ # 訪問所有變量的註解
{'a1': typing.List[int], 'a2': typing.List[str], 'b1': typing.Tuple[int], 'b2': typing.Tuple[float], 'c1': [typing.Dict[str, int]], 'l': typing.List[int], 'c2': [typing.Dict[str, int]]}
靜態類型檢查模塊mypy
既然解釋器不會對註解類型不匹配的情況進行報錯,那麼如何檢查類型不匹配的情況呢?
第三方模塊mypy就能做類型檢查,前提是要做好類型註解。具體舉例如下:
- 安裝mypy
pip install mypy
- 寫一個test.py程序,如下所示
def add(x: int, y: int) -> int:
return x+y
z: int
z = 'hello'
z = add(3.14, 1.23)
- 用mypy對test.py做類型檢查
在CMD裏,用命令mypy test.py
來檢查,可以看到輸出報錯信息如下:
mypy test.py
test.py:5: error: Incompatible types in assignment (expression has type "str", variable has type "int")
test.py:6: error: Argument 1 to "add" has incompatible type "float"; expected "int"
test.py:6: error: Argument 2 to "add" has incompatible type "float"; expected "int"
mypy提示
- 第5行1個錯誤,因爲z變量被申明爲int類型,但卻被賦值爲str的’hello’
- 第6行2個錯誤,因爲函數中兩個變量都被申明爲int,但這裏卻送入float類型的兩個數據
總結
python3.0 引入了函數註解,python3.6 引入了變量註解。以後這種語法可能會變,但筆者寫作時,在python3.7上實驗本文所述,是正確的。
它們都讓python越來越像C/C++了,將來python是否還會引入泛型呢?這樣python就越來越像Java了。。。
參考
- [1] PEP 3107 – Function Annotations. https://www.python.org/dev/peps/pep-3107/
- [2] https://zhuanlan.zhihu.com/p/37239021
- [3] PEP 526 – Syntax for Variable Annotations. https://www.python.org/dev/peps/pep-0526/