前言
類型注解讓 Python 代碼開起來丑不可言,但隨着用它的人越來越多,有時候會不可避免看到或是寫出來這樣的代碼:
def get_age(name: str) -> int:
...
雖然直觀上理解起來很方便,但是也有很多比較復雜的,不熟悉的人看起來可能不是很理解。比如:
class Thread:
name: str
ident: Optional[int]
daemon: bool
def __init__(self, group: None = ...,
target: Optional[Callable[..., Any]] = ...,
name: Optional[str] = ...,
args: Iterable = ...,
kwargs: Mapping[str, Any] = ...,
*, daemon: Optional[bool] = ...) -> None: ...
對類型注解有簡單的了解,可以方便我們看別人的代碼或是在自己的代碼中使用它。
簡單使用
Python 運行時不強制執行函數和變量類型注解,但這些注解可用於類型檢查器、IDE、靜態檢查器等第三方工具。有了類型注解,IDE 解析代碼也會更方便,提示也會更智能。簡單使用非常易於理解,比如下面的例子:
def greeting(name: str) -> str:
return 'Hello ' + name
這表示:greeting
函數中,參數 name
的類型是 str
,返回類型也是 str
。子類型也可以當作參數。
注解列表、集合等可迭代對象
GenericAlias 對象是通過對類(通常是容器類)作下標來創建的,如 list[int]
用來表示元素類型為 int
的列表。
通常,容器對象的抽取操作會調用該對象的
__getitem__()
方法。 但是,對某些容器類執行抽取操作可能會改去調用該類的__class_getitem__()
類方法。__class_getitem__()
類方法應當會返回一個GenericAlias
對象。
如果元素的類型不是固定的,那么可以使用 Union
或 |
來表示,比如要注解一個元素類型可能為 str
或 int
的列表,可以這樣寫:
from typing import Union, List
my_li: List[Union[str, int]]
# 或
my_li: List[str|int]
集合、元組或是自定義的可迭代對應同理。
如果要注解字典呢?
可以用如下方法:
from typing import Dict
my_dict: Dict[int, str]
這表示 my_dict
是一個鍵類型為 int
,值類型為 str
的字典。
注解可調用對象
預期特定簽名回調函數的框架可以用 Callable[[Arg1Type, Arg2Type], ReturnType]
實現類型提示。
比如,要注解一個可調用對象,它接收兩個參數,類型分別是 int
, str
,返回的類型是 list
,那么可以這樣寫:
from typing import Callable
func: Callable[[int, str], list]
另外,無需指定調用簽名,用省略號字面量替換類型提示里的參數列表: Callable[..., ReturnType]
,就可以聲明可調對象的返回類型。比如上面的例子也可以寫為:
from typing import Callable
func: Callable[..., list]
如果要注解沒有返回值的對象,可以使用 typing.NoReturn
:
from typing import Callable, NoReturn
func: Callable[..., NoReturn]
typing.NoReturn
同樣可以對函數返回注解,如:
def stop() -> NoReturn:
pass
注解常量
常量可以使用 Final
注解,比如:
from typing import Final
NAME: Final = 'Spartan'
對於不可被覆蓋的方法,可以用 final
裝飾器,例如:
from typing import final
class Foo:
@final
def finish(self):
pass
注解可選參數
使用 Optinal
可以注解可選參數,比如,注解名為 name
的可選參數:
from typing import Optional
def check(name: Optional[str]=None):
pass
泛型
有的類型實在難以描述?沒關系,可以使用 TypeVar
定義一個泛型,比如,要注解一個難以描述的類型(暫且稱之為 Puzzle
),那么可以這樣定義它:
from typing import TypeVar
Puzzle = TypeVar('Puzzle')
然后就可以用它來注解了:
name: Puzzle = ...
Any
Typing.Any
可以表示任意類型,此外,未指定返回值與參數類型的函數,都隱式地默認使用 Any
。
類型別名
把類型賦給別名,就可以定義類型別名。比如:
Vector = list[float]
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
參考
1. [typing --- 類型提示支持 — Python 3.10.1 文檔] (https://docs.python.org/zh-cn/3/library/typing.html)