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,或 explicitly return None,或 simply return

須注意的是,Python 的 type hints 是一種輔助用的功能,是給開發者和編輯器看的,不是給 Python Interpreter 看的,所以沒有 runtime checker,也不影響 Python 身為動態型別的本質。

換句話說,如果你用了 type hints,然後在程式碼裡面把一個 int assign 給型別為 str 的變數,還是可以執行(你只會在編輯器上看到五顏六色的警告)。

常用的 Types

Primitive Types

常用的 primitive types 包括:intfloatstrboolNone

Non-Primitive Types

常用的 non-primitive types 包括:TupleListSetDict

  • 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]

  • 型別可以是 XY,比如 Union[int, float, None]

  • 須先 from typing import Union,但在 Python 3.10 後可以用 X | Y 取代之。

Optional[X]

  • 型別可以是 XNone,比如 Optional[int]

  • 須先 from typing import Optional,但在 Python 3.10 後可以用 X | None 取代之。

Callable[[Arg1Type, Arg2Type], ReturnType]

若一個 function 的接收兩個型別分別為 Arg1TypeArg2Type 的參數,且 return 的型別為 ReturnType 的值,則該 function 的型別可以定義如上。

若想要定義一個「不限制參數的數量與型別」的 function,則可以寫:Callable[..., ReturnType]

ClassVar[T]

定義 class variable 時可以使用它,T 的部分就是原本的資料型態,比如 ClassVar[int]

After Python 3.8

Literal

規範某變數或 function 的回傳值只能為某些特定值,舉例如下:

from typing import Literal

def open_helper(file: str, mode: Literal["r", "rb", "w", "wb"]) -> str:
    ...

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 前,TupleListSetDict 等 types 要從 typing module import,不過 3.9 後可以直接使用 built-in 的 tuplelistsetdict 替代之,TupleListDict 等則變為 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 | None 取代 Optional[X]

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

定義一個名為 Point 的 type alias:

type Point = tuple[float, float]

也可以搭配 generic 使用:

type Point[T] = tuple[T, T]

參考資料

Last updated