Type Hints
Python 作為一個動態型別的語言,雖然享受著「開發速度快」及「容易上手」等美名,不過隨著專案越來越龐大,開發和 debug 的速度卻會因缺乏型別定義而下降,出現 bug 的機率也隨之上升。
不過 Python 自 3.5 推出後便導入 type hint,開始擁抱一些靜態型別的優點,舉例如下:
def greet(name: str) -> None:
print(f"Hello, my name is {name}.")
n: str = "Chris"
greet(n)
由上面的例子我們可以發現:
定義 variables 以及 parameters 時使用
: {TYPE}
定義 functions 時使用
-> {TYPE}
。當
None
用作 function 的 return type 時,意思是「沒有reurtn
statement,或 explicitlyreturn None
,或 simplyreturn
」
須注意的是,Python 的 type hints 是一種輔助用的功能,是給開發者和編輯器看的,不是給 Python Interpreter 看的,所以沒有 runtime checker,也不影響 Python 身為動態型別的本質。
換句話說,如果你用了 type hints,然後在程式碼裡面把一個 int
assign 給型別為 str
的變數,還是可以執行(你只會在編輯器上看到五顏六色的警告)。
常用的 Types
Primitive Types
常用的 primitive types 包括:int
、float
、str
、bool
、None
。
Non-Primitive Types
常用的 non-primitive types 包括:Tuple
、List
、Set
與 Dict
。
List[X]
:一個全部元素都是X
型別的 list,比如List[int]
Tuple[X]
:一個全部元素都是X
型別的 tuple,比如Tuple[int]
Tuple[X, ...]
:一個「第一個元素是X
型別」,「其餘元素可以是任何型別」的 tuple,比如Tuple[int, ...]
...
在這裡的意思不是懶得寫,而是一個叫 "ellipsis" 的語法。
Set[X]
:一個全部元素都是X
型別的 set,比如Set[int]
Dict[X, Y]
:一個全部的 key 型別都是X
,且全部的 value 型別都是Y
的 dict
[!Info] 上述的 non-primitive types 皆必須先
from typing import {TYPE}
才能使用,但在 Python 3.9 之後有 built-in types 可以取代之(就不用 import 了),詳見 此段。
Special Types
Union[X, Y]
型別可以是
X
或Y
,比如Union[int, float, None]
。須先
from typing import Union
,但在 Python 3.10 後可以用X | Y
取代之。
Optional[X]
型別可以是
X
或None
,比如Optional[int]
。須先
from typing import Optional
,但在 Python 3.10 後可以用X | None
取代之。
Callable[[Arg1Type, Arg2Type], ReturnType]
若一個 function 的接收兩個型別分別為 Arg1Type
與 Arg2Type
的參數,且 return 的型別為 ReturnType
的值,則該 function 的型別可以定義如上。
若想要定義一個「不限制參數的數量與型別」的 function,則可以寫:Callable[..., ReturnType]
。
ClassVar[T]
定義 class variable 時可以使用它,T
的部分就是原本的資料型態,比如 ClassVar[int]
。
After Python 3.8
Literal
Literal
規範某變數或 function 的回傳值只能為某些特定值,舉例如下:
from typing import Literal
def open_helper(file: str, mode: Literal["r", "rb", "w", "wb"]) -> str:
...
Final
Final
定義某變數為常數,效果類似 JavaScript 中的 const
,舉例如下:
from typing import Final
PI: Final[float] = 3.14159
PI = 0 # Error reported by type checker
[!Note] 注意 現在還無法檢查到
+=
等 Augmented Assignment,以上例而言,PI += 1
是不會出現錯誤提示的。
After Python 3.9
在 Python 3.9 前,Tuple
、List
、Set
、Dict
等 types 要從 typing
module import,不過 3.9 後可以直接使用 built-in 的 tuple
、list
、set
與 dict
替代之,Tuple
、List
、Dict
等則變為 deprecated,詳情請見 官方文件。
Before 3.9:
from typing import Tuple, List, Dict
a: Tuple[int] = (0, )
b: List[str] = ["a"]
c: Dict[str, int] = {"a": 0}
Since 3.9:
a: tuple[int] = (0, )
b: list[str] = ["a"]
c: dict[str, int] = {"a": 0}
After Python 3.10
X | Y
取代 Union[X, Y]
X | Y
取代 Union[X, Y]
X | None
取代 Optional[X]
X | None
取代 Optional[X]
TypeAlias
TypeAlias
可以把型別存成變數,舉例如下:
from typing import TypeAlias, Literal
MODE: TypeAlias = Literal["r", "rb", "w", "wb"]
def open_helper(file: str, mode: MODE) -> str:
...
After Python 3.12
type
Statement 取代 3.10 的 TypeAlias
type
Statement 取代 3.10 的 TypeAlias
定義一個名為 Point
的 type alias:
type Point = tuple[float, float]
也可以搭配 generic 使用:
type Point[T] = tuple[T, T]
參考資料
Last updated