詳解python3的新特性:函數註解(Function Annotations)與類型註解

引入

我們在閱讀python3寫的代碼時,會看到類似如下的程序:

def add(x: int, y: int) -> int:
    return x+y

初步看上去,與python2相比,這個函數在定義上,多了3個int。前兩個int表示輸入數據的類型,"->"符號後面的int,表示返回值類型。

在python中,是不用強制申明變量類型的。python3的這種新語法,貌似可以直接申明變量類型?

函數註解

  1. 函數註解的說明

這種“申明函數參數中變量類型,與返回值類型”的語法,就是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的設計者可以用來做代碼檢查。

  1. 如何訪問函數註解

我們如何得到某一個函數的類型註解呢?其實很簡單,使用__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以上的版本運行:

  1. 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'
  1. 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}

同理,不按註解的類型來,也不會報錯。

  1. 如何訪問變量註解

在程序中申明的所有註解變量,都可以由__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就能做類型檢查,前提是要做好類型註解。具體舉例如下:

  1. 安裝mypy
pip install mypy
  1. 寫一個test.py程序,如下所示
def add(x: int, y: int) -> int:
    return x+y

z: int
z = 'hello'
z = add(3.14, 1.23)
  1. 用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/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章