typing — 型別提示支援

在 3.5 版本加入。

原始碼: Lib/typing.py

備註

Python 執行時不強制函式和變數型別註解。它們可以被第三方工具使用,例如型別檢查器、IDE、linter 等。


本模組為型別提示提供執行時支援。

考慮下面的函式

def surface_area_of_cube(edge_length: float) -> str:
    return f"The surface area of the cube is {6 * edge_length ** 2}."

函式 surface_area_of_cube 接受一個預期為 float 例項的引數,如型別提示 edge_length: float 所示。該函式預期返回一個 str 例項,如 -> str 提示所示。

雖然型別提示可以是簡單的類,如 floatstr,但它們也可以更復雜。typing 模組提供了更高階的型別提示詞彙表。

typing 模組經常新增新功能。typing_extensions 包為舊版本的 Python 提供了這些新功能的向後移植。

參見

型別提示速查表

型別提示的快速概覽(託管在 mypy 文件中)

mypy 文件的型別系統參考部分

Python 型別系統透過 PEPs 進行標準化,因此本參考資料應廣泛適用於大多數 Python 型別檢查器。(某些部分可能仍然特定於 mypy。)

Python 靜態型別

由社群編寫的與型別檢查器無關的文件,詳細介紹了型別系統功能、有用的型別相關工具和型別提示最佳實踐。

Python 型別系統規範

Python 型別系統的規範(規範、最新)可在Python 型別系統規範中找到。

類型別名

類型別名使用 type 語句定義,該語句建立 TypeAliasType 的例項。在此示例中,Vectorlist[float] 將被靜態型別檢查器同等對待。

type Vector = list[float]

def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]

# passes type checking; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])

類型別名對於簡化複雜的型別簽名非常有用。例如

from collections.abc import Sequence

type ConnectionOptions = dict[str, str]
type Address = tuple[str, int]
type Server = tuple[Address, ConnectionOptions]

def broadcast_message(message: str, servers: Sequence[Server]) -> None:
    ...

# The static type checker will treat the previous type signature as
# being exactly equivalent to this one.
def broadcast_message(
    message: str,
    servers: Sequence[tuple[tuple[str, int], dict[str, str]]]
) -> None:
    ...

type 語句是 Python 3.12 中的新功能。為了向後相容,類型別名也可以透過簡單賦值建立

Vector = list[float]

或者用 TypeAlias 標記,以明確這是一個類型別名,而不是一個普通變數賦值。

from typing import TypeAlias

Vector: TypeAlias = list[float]

NewType

使用 NewType 輔助函式建立不同的型別

from typing import NewType

UserId = NewType('UserId', int)
some_id = UserId(524313)

靜態型別檢查器會將新型別視為原始型別的子類。這有助於捕獲邏輯錯誤

def get_user_name(user_id: UserId) -> str:
    ...

# passes type checking
user_a = get_user_name(UserId(42351))

# fails type checking; an int is not a UserId
user_b = get_user_name(-1)

您仍然可以在 UserId 型別的變數上執行所有 int 操作,但結果始終是 int 型別。這允許您在預期 int 的任何地方傳入 UserId,但會阻止您以無效方式意外建立 UserId

# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)

請注意,這些檢查僅由靜態型別檢查器強制執行。在執行時,語句 Derived = NewType('Derived', Base) 將使 Derived 成為一個可呼叫物件,它會立即返回您傳入的任何引數。這意味著表示式 Derived(some_value) 不會建立新類,也不會引入超出常規函式呼叫的大量開銷。

更準確地說,表示式 some_value is Derived(some_value) 在執行時始終為真。

建立 Derived 的子型別是無效的

from typing import NewType

UserId = NewType('UserId', int)

# Fails at runtime and does not pass type checking
class AdminUserId(UserId): pass

但是,可以基於“派生”的 NewType 建立 NewType

from typing import NewType

UserId = NewType('UserId', int)

ProUserId = NewType('ProUserId', UserId)

並且 ProUserId 的型別檢查將按預期工作。

有關更多詳細資訊,請參閱 PEP 484

備註

回想一下,使用類型別名聲明瞭兩個型別是 等價的 。執行 type Alias = Original 將使靜態型別檢查器在所有情況下都將 Alias 視為與 Original 完全等價 。當您想簡化複雜的型別簽名時,這很有用。

相反,NewType 聲明瞭一個型別是另一個型別的 子型別 。執行 Derived = NewType('Derived', Original) 將使靜態型別檢查器將 Derived 視為 Original子類 ,這意味著型別為 Original 的值不能用於預期型別為 Derived 的位置。當您想以最小的執行時成本防止邏輯錯誤時,這很有用。

3.5.2 版本新增。

3.10 版本中的更改: NewType 現在是一個類而不是一個函式。因此,與常規函式呼叫相比,呼叫 NewType 會產生一些額外的執行時成本。

3.11 版本中的更改: 呼叫 NewType 的效能已恢復到 Python 3.9 的水平。

註解可呼叫物件

函式——或其他可呼叫物件——可以使用 collections.abc.Callable 或已棄用的 typing.Callable 進行註解。Callable[[int], str] 表示一個接受一個 int 型別的引數並返回 str 的函式。

例如:

from collections.abc import Callable, Awaitable

def feeder(get_next_item: Callable[[], str]) -> None:
    ...  # Body

def async_query(on_success: Callable[[int], None],
                on_error: Callable[[int, Exception], None]) -> None:
    ...  # Body

async def on_update(value: str) -> None:
    ...  # Body

callback: Callable[[str], Awaitable[None]] = on_update

訂閱語法必須始終與恰好兩個值一起使用:引數列表和返回型別。引數列表必須是型別列表、ParamSpecConcatenate 或省略號(...)。返回型別必須是單個型別。

如果引數列表給定字面省略號 ...,則表示接受具有任意引數列表的可呼叫物件。

def concat(x: str, y: str) -> str:
    return x + y

x: Callable[..., str]
x = str     # OK
x = concat  # Also OK

Callable 無法表達複雜的簽名,例如接受可變數量引數的函式、過載函式或具有僅關鍵字引數的函式。但是,可以透過定義具有 __call__() 方法的 Protocol 類來表達這些簽名

from collections.abc import Iterable
from typing import Protocol

class Combiner(Protocol):
    def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ...

def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes:
    for item in data:
        ...

def good_cb(*vals: bytes, maxlen: int | None = None) -> list[bytes]:
    ...
def bad_cb(*vals: bytes, maxitems: int | None) -> list[bytes]:
    ...

batch_proc([], good_cb)  # OK
batch_proc([], bad_cb)   # Error! Argument 2 has incompatible type because of
                         # different name and kind in the callback

接受其他可呼叫物件作為引數的可呼叫物件可以使用 ParamSpec 指示它們的引數型別相互依賴。此外,如果該可呼叫物件新增或刪除其他可呼叫物件的引數,則可以使用 Concatenate 運算子。它們的形式分別為 Callable[ParamSpecVariable, ReturnType]Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType]

3.10 版本中的更改: Callable 現在支援 ParamSpecConcatenate。有關更多詳細資訊,請參閱 PEP 612

參見

ParamSpecConcatenate 的文件提供了 Callable 中的用法示例。

泛型

由於無法以通用方式靜態推斷容器中物件的型別資訊,標準庫中的許多容器類都支援訂閱來表示容器元素的預期型別。

from collections.abc import Mapping, Sequence

class Employee: ...

# Sequence[Employee] indicates that all elements in the sequence
# must be instances of "Employee".
# Mapping[str, str] indicates that all keys and all values in the mapping
# must be strings.
def notify_by_email(employees: Sequence[Employee],
                    overrides: Mapping[str, str]) -> None: ...

泛型函式和類可以使用型別引數語法進行引數化。

from collections.abc import Sequence

def first[T](l: Sequence[T]) -> T:  # Function is generic over the TypeVar "T"
    return l[0]

或者直接使用 TypeVar 工廠

from collections.abc import Sequence
from typing import TypeVar

U = TypeVar('U')                  # Declare type variable "U"

def second(l: Sequence[U]) -> U:  # Function is generic over the TypeVar "U"
    return l[1]

3.12 版本中的更改: 泛型的語法支援是 Python 3.12 中的新功能。

註解元組

對於 Python 中的大多數容器,型別系統假定容器中的所有元素都具有相同的型別。例如

from collections.abc import Mapping

# Type checker will infer that all elements in ``x`` are meant to be ints
x: list[int] = []

# Type checker error: ``list`` only accepts a single type argument:
y: list[int, str] = [1, 'foo']

# Type checker will infer that all keys in ``z`` are meant to be strings,
# and that all values in ``z`` are meant to be either strings or ints
z: Mapping[str, str | int] = {}

list 只接受一個型別引數,因此型別檢查器將在上面的 y 賦值上發出錯誤。類似地,Mapping 只接受兩個型別引數:第一個表示鍵的型別,第二個表示值的型別。

然而,與其他大多數 Python 容器不同,在地道的 Python 程式碼中,元組的元素不都是相同型別是很常見的。因此,元組在 Python 的型別系統中是特殊處理的。tuple 接受 任意數量 的型別引數

# OK: ``x`` is assigned to a tuple of length 1 where the sole element is an int
x: tuple[int] = (5,)

# OK: ``y`` is assigned to a tuple of length 2;
# element 1 is an int, element 2 is a str
y: tuple[int, str] = (5, "foo")

# Error: the type annotation indicates a tuple of length 1,
# but ``z`` has been assigned to a tuple of length 3
z: tuple[int] = (1, 2, 3)

要表示長度 任意 且所有元素都具有相同型別 T 的元組,請使用字面省略號 ...tuple[T, ...]。要表示空元組,請使用 tuple[()]。使用純 tuple 作為註解等同於使用 tuple[Any, ...]

x: tuple[int, ...] = (1, 2)
# These reassignments are OK: ``tuple[int, ...]`` indicates x can be of any length
x = (1, 2, 3)
x = ()
# This reassignment is an error: all elements in ``x`` must be ints
x = ("foo", "bar")

# ``y`` can only ever be assigned to an empty tuple
y: tuple[()] = ()

z: tuple = ("foo", "bar")
# These reassignments are OK: plain ``tuple`` is equivalent to ``tuple[Any, ...]``
z = (1, 2, 3)
z = ()

類物件的型別

使用 C 註解的變數可以接受型別為 C 的值。相反,使用 type[C](或已棄用的 typing.Type[C])註解的變數可以接受本身就是類的值——具體來說,它將接受 C類物件。例如

a = 3         # Has type ``int``
b = int       # Has type ``type[int]``
c = type(a)   # Also has type ``type[int]``

請注意,type[C] 是協變的

class User: ...
class ProUser(User): ...
class TeamUser(User): ...

def make_new_user(user_class: type[User]) -> User:
    # ...
    return user_class()

make_new_user(User)      # OK
make_new_user(ProUser)   # Also OK: ``type[ProUser]`` is a subtype of ``type[User]``
make_new_user(TeamUser)  # Still fine
make_new_user(User())    # Error: expected ``type[User]`` but got ``User``
make_new_user(int)       # Error: ``type[int]`` is not a subtype of ``type[User]``

type 的唯一合法引數是類、Any型別變數以及這些型別中的任意一種的聯合。例如

def new_non_team_user(user_class: type[BasicUser | ProUser]): ...

new_non_team_user(BasicUser)  # OK
new_non_team_user(ProUser)    # OK
new_non_team_user(TeamUser)   # Error: ``type[TeamUser]`` is not a subtype
                              # of ``type[BasicUser | ProUser]``
new_non_team_user(User)       # Also an error

type[Any] 等同於 type,它是 Python 元類層次結構的根。

註解生成器和協程

生成器可以使用泛型型別 Generator[YieldType, SendType, ReturnType] 進行註解。例如

def echo_round() -> Generator[int, float, str]:
    sent = yield 0
    while sent >= 0:
        sent = yield round(sent)
    return 'Done'

請注意,與標準庫中許多其他泛型類不同,GeneratorSendType 行為是逆變而不是協變或不變。

SendTypeReturnType 引數預設為 None

def infinite_stream(start: int) -> Generator[int]:
    while True:
        yield start
        start += 1

也可以明確設定這些型別

def infinite_stream(start: int) -> Generator[int, None, None]:
    while True:
        yield start
        start += 1

僅生成值的簡單生成器也可以註解為返回型別為 Iterable[YieldType]Iterator[YieldType]

def infinite_stream(start: int) -> Iterator[int]:
    while True:
        yield start
        start += 1

非同步生成器以類似的方式處理,但不期望 ReturnType 型別引數(AsyncGenerator[YieldType, SendType])。SendType 引數預設為 None,因此以下定義是等價的

async def infinite_stream(start: int) -> AsyncGenerator[int]:
    while True:
        yield start
        start = await increment(start)

async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
    while True:
        yield start
        start = await increment(start)

與同步情況一樣,AsyncIterable[YieldType]AsyncIterator[YieldType] 也可用

async def infinite_stream(start: int) -> AsyncIterator[int]:
    while True:
        yield start
        start = await increment(start)

協程可以使用 Coroutine[YieldType, SendType, ReturnType] 進行註解。泛型引數與 Generator 的引數相對應,例如

from collections.abc import Coroutine
c: Coroutine[list[str], str, int]  # Some coroutine defined elsewhere
x = c.send('hi')                   # Inferred type of 'x' is list[str]
async def bar() -> None:
    y = await c                    # Inferred type of 'y' is int

使用者定義的泛型型別

使用者定義的類可以定義為泛型類。

from logging import Logger

class LoggedVar[T]:
    def __init__(self, value: T, name: str, logger: Logger) -> None:
        self.name = name
        self.logger = logger
        self.value = value

    def set(self, new: T) -> None:
        self.log('Set ' + repr(self.value))
        self.value = new

    def get(self) -> T:
        self.log('Get ' + repr(self.value))
        return self.value

    def log(self, message: str) -> None:
        self.logger.info('%s: %s', self.name, message)

此語法表示類 LoggedVar 是圍繞單個 型別變數 T 引數化的。這也使得 T 在類主體內作為型別有效。

泛型類隱式繼承自 Generic。為了與 Python 3.11 及更低版本相容,也可以顯式繼承自 Generic 以指示泛型類。

from typing import TypeVar, Generic

T = TypeVar('T')

class LoggedVar(Generic[T]):
    ...

泛型類具有 __class_getitem__() 方法,這意味著它們可以在執行時進行引數化(例如下面的 LoggedVar[int]

from collections.abc import Iterable

def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
    for var in vars:
        var.set(0)

泛型型別可以有任意數量的型別變數。TypeVar 的所有變體都可以作為泛型型別的引數

from typing import TypeVar, Generic, Sequence

class WeirdTrio[T, B: Sequence[bytes], S: (int, str)]:
    ...

OldT = TypeVar('OldT', contravariant=True)
OldB = TypeVar('OldB', bound=Sequence[bytes], covariant=True)
OldS = TypeVar('OldS', int, str)

class OldWeirdTrio(Generic[OldT, OldB, OldS]):
    ...

傳遞給 Generic 的每個型別變數引數都必須是唯一的。因此,這是無效的

from typing import TypeVar, Generic
...

class Pair[M, M]:  # SyntaxError
    ...

T = TypeVar('T')

class Pair(Generic[T, T]):   # INVALID
    ...

泛型類也可以繼承自其他類

from collections.abc import Sized

class LinkedList[T](Sized):
    ...

繼承泛型類時,某些型別引數可以固定。

from collections.abc import Mapping

class MyDict[T](Mapping[str, T]):
    ...

在這種情況下,MyDict 有一個引數,T

使用不指定型別引數的泛型類將為每個位置假定 Any。在以下示例中,MyIterable 不是泛型類,但隱式繼承自 Iterable[Any]

from collections.abc import Iterable

class MyIterable(Iterable): # Same as Iterable[Any]
    ...

也支援使用者定義的泛型類型別名。例如

from collections.abc import Iterable

type Response[S] = Iterable[S] | int

# Return type here is same as Iterable[str] | int
def response(query: str) -> Response[str]:
    ...

type Vec[T] = Iterable[tuple[T, T]]

def inproduct[T: (int, float, complex)](v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
    return sum(x*y for x, y in v)

為了向後相容,泛型類型別名也可以透過簡單賦值建立。

from collections.abc import Iterable
from typing import TypeVar

S = TypeVar("S")
Response = Iterable[S] | int

3.7 版本中的更改: Generic 不再具有自定義元類。

3.12 版本中的更改: 泛型和類型別名的語法支援是 3.12 版本中的新功能。以前,泛型類必須顯式繼承自 Generic 或在其某個基類中包含型別變數。

還透過引數規範變數以 [**P] 形式支援用於引數表示式的使用者定義泛型。其行為與上面描述的型別變數一致,因為 typing 模組將引數規範變數視為特殊化的型別變數。唯一的例外是可以使用型別列表來替換 ParamSpec

>>> class Z[T, **P]: ...  # T is a TypeVar; P is a ParamSpec
...
>>> Z[int, [dict, float]]
__main__.Z[int, [dict, float]]

泛型類 over ParamSpec 也可以透過顯式繼承自 Generic 建立。在這種情況下,不使用 **

from typing import ParamSpec, Generic

P = ParamSpec('P')

class Z(Generic[P]):
    ...

TypeVarParamSpec 之間的另一個區別是,只有一個引數規範變數的泛型將接受 X[[Type1, Type2, ...]] 形式的引數列表,以及出於美觀原因的 X[Type1, Type2, ...] 形式。在內部,後者被轉換為前者,因此以下兩者是等價的

>>> class X[**P]: ...
...
>>> X[int, str]
__main__.X[[int, str]]
>>> X[[int, str]]
__main__.X[[int, str]]

請注意,帶有 ParamSpec 的泛型在某些情況下在替換後可能沒有正確的 __parameters__,因為它們主要用於靜態型別檢查。

3.10 版本中的更改: Generic 現在可以引數化引數表示式。有關更多詳細資訊,請參閱 ParamSpecPEP 612

使用者定義的泛型類可以具有 ABCs 作為基類,而不會發生元類衝突。不支援泛型元類。引數化泛型的結果被快取,並且 typing 模組中的大多數型別都是可雜湊的並且在相等性方面可比較。

Any 型別

一種特殊型別的型別是 Any。靜態型別檢查器將把所有型別視為與 Any 相容,並將 Any 視為與所有型別相容。

這意味著可以對 Any 型別的值執行任何操作或方法呼叫,並將其賦值給任何變數。

from typing import Any

a: Any = None
a = []          # OK
a = 2           # OK

s: str = ''
s = a           # OK

def foo(item: Any) -> int:
    # Passes type checking; 'item' could be any type,
    # and that type might have a 'bar' method
    item.bar()
    ...

請注意,將 Any 型別的值分配給更精確的型別時,不會執行型別檢查。例如,即使 s 被宣告為 str 型別,並在執行時接收到一個 int 值,靜態型別檢查器在將 a 分配給 s 時也沒有報告錯誤!

此外,所有沒有返回型別或引數型別的函式將隱式預設使用 Any

def legacy_parser(text):
    ...
    return data

# A static type checker will treat the above
# as having the same signature as:
def legacy_parser(text: Any) -> Any:
    ...
    return data

這種行為允許 Any 作為 逃逸出口 使用,當您需要混合動態和靜態型別程式碼時。

Any 的行為與 object 的行為進行對比。與 Any 類似,所有型別都是 object 的子型別。然而,與 Any 不同,反之則不然:object 不是 所有其他型別的子型別。

這意味著當一個值的型別是 object 時,型別檢查器將拒絕對其進行幾乎所有操作,將其分配給更專業型別的變數(或將其用作返回值)將是型別錯誤。例如

def hash_a(item: object) -> int:
    # Fails type checking; an object does not have a 'magic' method.
    item.magic()
    ...

def hash_b(item: Any) -> int:
    # Passes type checking
    item.magic()
    ...

# Passes type checking, since ints and strs are subclasses of object
hash_a(42)
hash_a("foo")

# Passes type checking, since Any is compatible with all types
hash_b(42)
hash_b("foo")

使用 object 以型別安全的方式指示一個值可以是任何型別。使用 Any 以指示一個值是動態型別的。

名義子型別與結構子型別

最初 PEP 484 將 Python 靜態型別系統定義為使用 名義子型別。這意味著如果且僅當 AB 的子類時,允許在預期類 B 的位置使用類 A

此要求以前也適用於抽象基類,例如 Iterable。這種方法的缺點是類必須明確標記以支援它們,這不符合 Python 風格,也不像在習慣的動態型別 Python 程式碼中通常會做的那樣。例如,這符合 PEP 484

from collections.abc import Sized, Iterable, Iterator

class Bucket(Sized, Iterable[int]):
    ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[int]: ...

PEP 544 允許透過允許使用者在類定義中編寫上述程式碼而無需顯式基類來解決此問題,從而允許靜態型別檢查器將 Bucket 隱式視為 SizedIterable[int] 的子型別。這被稱為 結構子型別(或靜態鴨子型別)。

from collections.abc import Iterator, Iterable

class Bucket:  # Note: no base classes
    ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[int]: ...

def collect(items: Iterable[int]) -> int: ...
result = collect(Bucket())  # Passes type check

此外,透過繼承特殊的類 Protocol,使用者可以定義新的自定義協議以充分利用結構子型別(參見下面的示例)。

模組內容

typing 模組定義了以下類、函式和裝飾器。

特殊型別提示原語

特殊型別

這些可用作註解中的型別。它們不支援使用 [] 進行訂閱。

typing.Any

表示無約束型別的特殊型別。

  • 所有型別都與 Any 相容。

  • Any 與所有型別相容。

3.11 版本中的更改: Any 現在可以用作基類。這對於避免型別檢查器對可以隨處進行鴨子型別化或高度動態的類產生錯誤非常有用。

typing.AnyStr

一個 受限型別變數

定義

AnyStr = TypeVar('AnyStr', str, bytes)

AnyStr 旨在用於可能接受 strbytes 引數但不能允許兩者混用的函式。

例如:

def concat(a: AnyStr, b: AnyStr) -> AnyStr:
    return a + b

concat("foo", "bar")    # OK, output has type 'str'
concat(b"foo", b"bar")  # OK, output has type 'bytes'
concat("foo", b"bar")   # Error, cannot mix str and bytes

請注意,儘管其名稱如此,AnyStrAny 型別無關,也不表示“任何字串”。特別是,AnyStrstr | bytes 彼此不同,並且具有不同的用例

# Invalid use of AnyStr:
# The type variable is used only once in the function signature,
# so cannot be "solved" by the type checker
def greet_bad(cond: bool) -> AnyStr:
    return "hi there!" if cond else b"greetings!"

# The better way of annotating this function:
def greet_proper(cond: bool) -> str | bytes:
    return "hi there!" if cond else b"greetings!"

自 3.13 版棄用,並將在 3.18 版中移除: 已棄用,轉而使用新的型別引數語法。使用 class A[T: (str, bytes)]: ... 而不是匯入 AnyStr。有關更多詳細資訊,請參閱 PEP 695

在 Python 3.16 中,AnyStr 將從 typing.__all__ 中移除,並且在從 typing 訪問或匯入它時,將在執行時發出棄用警告。AnyStr 將在 Python 3.18 中從 typing 中移除。

typing.LiteralString

只包含字面字串的特殊型別。

任何字串字面量都與 LiteralString 相容,另一個 LiteralString 也是如此。但是,僅鍵入為 str 的物件則不相容。透過組合 LiteralString 型別的物件建立的字串也可用作 LiteralString

示例

def run_query(sql: LiteralString) -> None:
    ...

def caller(arbitrary_string: str, literal_string: LiteralString) -> None:
    run_query("SELECT * FROM students")  # OK
    run_query(literal_string)  # OK
    run_query("SELECT * FROM " + literal_string)  # OK
    run_query(arbitrary_string)  # type checker error
    run_query(  # type checker error
        f"SELECT * FROM students WHERE name = {arbitrary_string}"
    )

LiteralString 對於敏感的 API 很有用,其中任意使用者生成的字串可能會產生問題。例如,上面兩個會生成型別檢查器錯誤的案例可能會受到 SQL 注入攻擊。

有關更多詳細資訊,請參閱 PEP 675

在 3.11 版本中新增。

typing.Never
typing.NoReturn

NeverNoReturn 代表 底部型別,一個沒有成員的型別。

它們可用於指示函式永不返回,例如 sys.exit()

from typing import Never  # or NoReturn

def stop() -> Never:
    raise RuntimeError('no way')

或者定義一個永遠不應被呼叫的函式,因為沒有有效的引數,例如 assert_never()

from typing import Never  # or NoReturn

def never_call_me(arg: Never) -> None:
    pass

def int_or_str(arg: int | str) -> None:
    never_call_me(arg)  # type checker error
    match arg:
        case int():
            print("It's an int")
        case str():
            print("It's a str")
        case _:
            never_call_me(arg)  # OK, arg is of type Never (or NoReturn)

NeverNoReturn 在型別系統中具有相同的含義,靜態型別檢查器將兩者同等對待。

3.6.2 版本新增: 增加了 NoReturn

3.11 版本新增: 增加了 Never

typing.Self

表示當前封閉類的特殊型別。

例如:

from typing import Self, reveal_type

class Foo:
    def return_self(self) -> Self:
        ...
        return self

class SubclassOfFoo(Foo): pass

reveal_type(Foo().return_self())  # Revealed type is "Foo"
reveal_type(SubclassOfFoo().return_self())  # Revealed type is "SubclassOfFoo"

此註解在語義上等同於以下內容,儘管方式更簡潔

from typing import TypeVar

Self = TypeVar("Self", bound="Foo")

class Foo:
    def return_self(self: Self) -> Self:
        ...
        return self

通常,如果某個方法返回 self,如上述示例所示,您應該使用 Self 作為返回註解。如果 Foo.return_self 被註解為返回 "Foo",那麼型別檢查器將推斷 SubclassOfFoo.return_self 返回的物件型別為 Foo 而不是 SubclassOfFoo

其他常見用例包括

  • 用作替代建構函式並返回 cls 引數例項的 classmethod

  • 註解返回自身的 __enter__() 方法。

如果方法不保證在子類化時返回子類的例項,則不應使用 Self 作為返回註解。

class Eggs:
    # Self would be an incorrect return annotation here,
    # as the object returned is always an instance of Eggs,
    # even in subclasses
    def returns_eggs(self) -> "Eggs":
        return Eggs()

有關更多詳細資訊,請參閱 PEP 673

在 3.11 版本中新增。

typing.TypeAlias

明確宣告類型別名的特殊註解。

例如:

from typing import TypeAlias

Factors: TypeAlias = list[int]

TypeAlias 在較舊的 Python 版本上特別有用,用於註解使用前向引用的別名,因為型別檢查器很難將這些與普通變數賦值區分開來。

from typing import Generic, TypeAlias, TypeVar

T = TypeVar("T")

# "Box" does not exist yet,
# so we have to use quotes for the forward reference on Python <3.12.
# Using ``TypeAlias`` tells the type checker that this is a type alias declaration,
# not a variable assignment to a string.
BoxOfStrings: TypeAlias = "Box[str]"

class Box(Generic[T]):
    @classmethod
    def make_box_of_strings(cls) -> BoxOfStrings: ...

有關更多詳細資訊,請參閱 PEP 613

在 3.10 版本加入。

自 3.12 版棄用: TypeAlias 已棄用,取而代之的是 type 語句,該語句建立 TypeAliasType 的例項,並原生支援前向引用。請注意,雖然 TypeAliasTypeAliasType 具有相似的用途和名稱,但它們是不同的,後者不是前者的型別。目前沒有計劃移除 TypeAlias,但建議使用者遷移到 type 語句。

特殊形式

這些可用作註解中的型別。它們都支援使用 [] 進行訂閱,但每個都具有獨特的語法。

class typing.Union

聯合型別;Union[X, Y] 等同於 X | Y,表示 X 或 Y。

要定義聯合,請使用例如 Union[int, str] 或簡寫 int | str。建議使用簡寫。詳細資訊

  • 引數必須是型別,並且必須至少有一個。

  • 聯合的聯合會被展平,例如

    Union[Union[int, str], float] == Union[int, str, float]
    

    但是,這不適用於透過類型別名引用的聯合,以避免強制評估底層 TypeAliasType

    type A = Union[int, str]
    Union[A, float] != Union[int, str, float]
    
  • 單個引數的聯合會消失,例如

    Union[int] == int  # The constructor actually returns int
    
  • 冗餘引數會被跳過,例如

    Union[int, str, int] == Union[int, str] == int | str
    
  • 比較聯合時,引數順序將被忽略,例如

    Union[int, str] == Union[str, int]
    
  • 您不能子類化或例項化 Union

  • 您不能寫入 Union[X][Y]

3.7 版本中的更改: 在執行時不從聯合中移除顯式子類。

3.10 版本中的更改: 聯合現在可以寫為 X | Y。請參閱聯合型別表示式

3.14 版本中的更改: types.UnionType 現在是 Union 的別名,並且 Union[int, str]int | str 都建立同一類的例項。要在執行時檢查物件是否為 Union,請使用 isinstance(obj, Union)。為了與 Python 的早期版本相容,請使用 get_origin(obj) is typing.Union or get_origin(obj) is types.UnionType

typing.Optional

Optional[X] 等同於 X | None(或 Union[X, None])。

請注意,這與可選引數的概念不同,可選引數是具有預設值的引數。具有預設值的可選引數不需要其型別註解上的 Optional 限定符,僅僅因為它可選。例如

def foo(arg: int = 0) -> None:
    ...

另一方面,如果允許 None 的顯式值,則使用 Optional 是合適的,無論引數是否可選。例如

def foo(arg: Optional[int] = None) -> None:
    ...

3.10 版本中的更改: Optional 現在可以寫為 X | None。請參閱聯合型別表示式

typing.Concatenate

用於註解高階函式的特殊形式。

Concatenate 可以與 CallableParamSpec 結合使用,以註解一個新增、移除或轉換另一個可呼叫物件引數的高階可呼叫物件。用法形式為 Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]Concatenate 目前僅在用作 Callable 的第一個引數時有效。Concatenate 的最後一個引數必須是 ParamSpec 或省略號(...)。

例如,要註解一個裝飾器 with_lock,它為被裝飾函式提供一個 threading.Lock,可以使用 Concatenate 來指示 with_lock 期望一個可呼叫物件,該物件以 Lock 作為第一個引數,並返回一個具有不同型別簽名的可呼叫物件。在這種情況下,ParamSpec 表示返回的可呼叫物件的引數型別取決於傳入的可呼叫物件的引數型別。

from collections.abc import Callable
from threading import Lock
from typing import Concatenate

# Use this lock to ensure that only one thread is executing a function
# at any time.
my_lock = Lock()

def with_lock[**P, R](f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]:
    '''A type-safe decorator which provides a lock.'''
    def inner(*args: P.args, **kwargs: P.kwargs) -> R:
        # Provide the lock as the first argument.
        return f(my_lock, *args, **kwargs)
    return inner

@with_lock
def sum_threadsafe(lock: Lock, numbers: list[float]) -> float:
    '''Add a list of numbers together in a thread-safe manner.'''
    with lock:
        return sum(numbers)

# We don't need to pass in the lock ourselves thanks to the decorator.
sum_threadsafe([1.1, 2.2, 3.3])

在 3.10 版本加入。

參見

typing.Literal

用於定義“字面量型別”的特殊型別形式。

Literal 可用於向型別檢查器指示註解物件的值等同於提供的字面量之一。

例如:

def validate_simple(data: Any) -> Literal[True]:  # always returns True
    ...

type Mode = Literal['r', 'rb', 'w', 'wb']
def open_helper(file: str, mode: Mode) -> str:
    ...

open_helper('/some/path', 'r')      # Passes type check
open_helper('/other/path', 'typo')  # Error in type checker

Literal[...] 不能被子類化。在執行時,任意值都可以作為 Literal[...] 的型別引數,但型別檢查器可能會施加限制。有關字面量型別的更多詳細資訊,請參閱 PEP 586

附加詳情

  • 引數必須是字面量值,並且必須至少有一個。

  • 巢狀的 Literal 型別會被展平,例如

    assert Literal[Literal[1, 2], 3] == Literal[1, 2, 3]
    

    但是,這不適用於透過類型別名引用的 Literal 型別,以避免強制評估底層 TypeAliasType

    type A = Literal[1, 2]
    assert Literal[A, 3] != Literal[1, 2, 3]
    
  • 冗餘引數會被跳過,例如

    assert Literal[1, 2, 1] == Literal[1, 2]
    
  • 比較字面量時,引數順序將被忽略,例如

    assert Literal[1, 2] == Literal[2, 1]
    
  • 您不能子類化或例項化 Literal

  • 您不能寫入 Literal[X][Y]

在 3.8 版本加入。

3.9.1 版本中的更改: Literal 現在會去重引數。Literal 物件的相等比較不再依賴於順序。Literal 物件現在在相等比較期間如果其引數之一不可雜湊,則會引發 TypeError 異常。

typing.ClassVar

用於標記類變數的特殊型別構造。

PEP 526 中所介紹,用 ClassVar 包裝的變數註解表示給定屬性旨在用作類變數,並且不應在類的例項上設定。用法

class Starship:
    stats: ClassVar[dict[str, int]] = {} # class variable
    damage: int = 10                     # instance variable

ClassVar 只接受型別,不能進一步訂閱。

ClassVar 本身不是一個類,不應與 isinstance()issubclass() 一起使用。ClassVar 不會改變 Python 執行時行為,但可以被第三方型別檢查器使用。例如,型別檢查器可能會將以下程式碼標記為錯誤

enterprise_d = Starship(3000)
enterprise_d.stats = {} # Error, setting class variable on instance
Starship.stats = {}     # This is OK

3.5.3 版本新增。

3.13 版本中的更改: ClassVar 現在可以巢狀在 Final 中,反之亦然。

typing.Final

用於向型別檢查器指示最終名稱的特殊型別構造。

最終名稱不能在任何作用域中重新賦值。在類作用域中宣告的最終名稱不能在子類中被覆蓋。

例如:

MAX_SIZE: Final = 9000
MAX_SIZE += 1  # Error reported by type checker

class Connection:
    TIMEOUT: Final[int] = 10

class FastConnector(Connection):
    TIMEOUT = 1  # Error reported by type checker

這些屬性沒有執行時檢查。有關更多詳細資訊,請參閱 PEP 591

在 3.8 版本加入。

3.13 版本中的更改: Final 現在可以巢狀在 ClassVar 中,反之亦然。

typing.Required

用於將 TypedDict 鍵標記為必需的特殊型別構造。

這主要用於 total=False 的 TypedDicts。有關更多詳細資訊,請參閱 TypedDictPEP 655

在 3.11 版本中新增。

typing.NotRequired

用於將 TypedDict 鍵標記為可能缺失的特殊型別構造。

有關更多詳細資訊,請參閱 TypedDictPEP 655

在 3.11 版本中新增。

typing.ReadOnly

一個特殊的型別構造,用於將 TypedDict 的項標記為只讀。

例如:

class Movie(TypedDict):
   title: ReadOnly[str]
   year: int

def mutate_movie(m: Movie) -> None:
   m["year"] = 1999  # allowed
   m["title"] = "The Matrix"  # typechecker error

此屬性沒有執行時檢查。

有關更多詳細資訊,請參閱 TypedDictPEP 705

在 3.13 版本加入。

typing.Annotated

用於向註解新增上下文特定元資料的特殊型別形式。

透過使用註解 Annotated[T, x] 將元資料 x 新增到給定型別 T。使用 Annotated 新增的元資料可用於靜態分析工具或在執行時。在執行時,元資料儲存在 __metadata__ 屬性中。

如果庫或工具遇到註解 Annotated[T, x] 並且對元資料沒有特殊邏輯,它應該忽略元資料並簡單地將註解視為 T。因此,當代碼希望將註解用於 Python 靜態型別系統之外的目的時,Annotated 會很有用。

使用 Annotated[T, x] 作為註解仍然允許對 T 進行靜態型別檢查,因為型別檢查器將簡單地忽略元資料 x。透過這種方式,Annotated@no_type_check 裝飾器不同,後者也可以用於在型別系統範圍之外添加註解,但會完全停用函式或類的型別檢查。

如何解釋元資料的責任在於遇到 Annotated 註解的工具或庫。遇到 Annotated 型別的工具或庫可以掃描元資料元素以確定它們是否感興趣(例如,使用 isinstance())。

Annotated[<type>, <metadata>]

這是一個示例,說明如何在進行範圍分析時使用 Annotated 向型別註解新增元資料。

@dataclass
class ValueRange:
    lo: int
    hi: int

T1 = Annotated[int, ValueRange(-10, 5)]
T2 = Annotated[T1, ValueRange(-20, 3)]

Annotated 的第一個引數必須是有效型別。可以提供多個元資料元素,因為 Annotated 支援可變引數。元資料元素的順序會保留並影響相等性檢查。

@dataclass
class ctype:
     kind: str

a1 = Annotated[int, ValueRange(3, 10), ctype("char")]
a2 = Annotated[int, ctype("char"), ValueRange(3, 10)]

assert a1 != a2  # Order matters

由使用註解的工具決定是否允許客戶端向一個註解新增多個元資料元素以及如何合併這些註解。

巢狀的 Annotated 型別會被展平。元資料元素的順序從最內層註解開始

assert Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
    int, ValueRange(3, 10), ctype("char")
]

但是,這不適用於透過類型別名引用的 Annotated 型別,以避免強制評估底層 TypeAliasType

type From3To10[T] = Annotated[T, ValueRange(3, 10)]
assert Annotated[From3To10[int], ctype("char")] != Annotated[
   int, ValueRange(3, 10), ctype("char")
]

重複的元資料元素不會被移除。

assert Annotated[int, ValueRange(3, 10)] != Annotated[
    int, ValueRange(3, 10), ValueRange(3, 10)
]

Annotated 可用於巢狀和泛型別名

@dataclass
class MaxLen:
    value: int

type Vec[T] = Annotated[list[tuple[T, T]], MaxLen(10)]

# When used in a type annotation, a type checker will treat "V" the same as
# ``Annotated[list[tuple[int, int]], MaxLen(10)]``:
type V = Vec[int]

Annotated 不能與解包的 TypeVarTuple 一起使用

type Variadic[*Ts] = Annotated[*Ts, Ann1] = Annotated[T1, T2, T3, ..., Ann1]  # NOT valid

其中 T1T2 等是 TypeVars。這是無效的,因為只能向 Annotated 傳遞一個型別。

預設情況下,get_type_hints() 會從註解中去除元資料。傳入 include_extras=True 以保留元資料。

>>> from typing import Annotated, get_type_hints
>>> def func(x: Annotated[int, "metadata"]) -> None: pass
...
>>> get_type_hints(func)
{'x': <class 'int'>, 'return': <class 'NoneType'>}
>>> get_type_hints(func, include_extras=True)
{'x': typing.Annotated[int, 'metadata'], 'return': <class 'NoneType'>}

在執行時,與 Annotated 型別關聯的元資料可以透過 __metadata__ 屬性檢索

>>> from typing import Annotated
>>> X = Annotated[int, "very", "important", "metadata"]
>>> X
typing.Annotated[int, 'very', 'important', 'metadata']
>>> X.__metadata__
('very', 'important', 'metadata')

如果要檢索由 Annotated 包裝的原始型別,請使用 __origin__ 屬性

>>> from typing import Annotated, get_origin
>>> Password = Annotated[str, "secret"]
>>> Password.__origin__
<class 'str'>

請注意,使用 get_origin() 將返回 Annotated 本身。

>>> get_origin(Password)
typing.Annotated

參見

PEP 593 - 靈活的函式和變數註解

PEP 將 Annotated 引入標準庫。

在 3.9 版本中新增。

typing.TypeIs

用於標記使用者定義的型別謂詞函式的特殊型別構造。

TypeIs 可用於註解使用者定義的型別謂詞函式的返回型別。TypeIs 只接受一個型別引數。在執行時,以這種方式標記的函式應返回布林值並至少接受一個位置引數。

TypeIs 旨在有利於 型別窄化 —— 靜態型別檢查器用來確定程式程式碼流中表達式更精確型別的一種技術。通常,型別窄化是透過分析條件程式碼流並將窄化應用於程式碼塊來完成的。這裡的條件表示式有時被稱為“型別謂詞”。

def is_str(val: str | float):
    # "isinstance" type predicate
    if isinstance(val, str):
        # Type of ``val`` is narrowed to ``str``
        ...
    else:
        # Else, type of ``val`` is narrowed to ``float``.
        ...

有時使用使用者定義的布林函式作為型別謂詞會很方便。這樣的函式應該使用 TypeIs[...]TypeGuard 作為其返回型別,以提醒靜態型別檢查器此意圖。TypeIs 通常比 TypeGuard 具有更直觀的行為,但當輸入和輸出型別不相容(例如,list[object]list[int])或當函式不為窄化型別的所有例項返回 True 時,它不能使用。

使用 -> TypeIs[NarrowedType] 可以告訴靜態型別檢查器,對於給定函式

  1. 其返回值是一個布林值。

  2. 如果返回值為 True,則其引數的型別是引數原始型別和 NarrowedType 的交集。

  3. 如果返回值為 False,則其引數的型別將被縮小以排除 NarrowedType

例如:

from typing import assert_type, final, TypeIs

class Parent: pass
class Child(Parent): pass
@final
class Unrelated: pass

def is_parent(val: object) -> TypeIs[Parent]:
    return isinstance(val, Parent)

def run(arg: Child | Unrelated):
    if is_parent(arg):
        # Type of ``arg`` is narrowed to the intersection
        # of ``Parent`` and ``Child``, which is equivalent to
        # ``Child``.
        assert_type(arg, Child)
    else:
        # Type of ``arg`` is narrowed to exclude ``Parent``,
        # so only ``Unrelated`` is left.
        assert_type(arg, Unrelated)

TypeIs 中的型別必須與函式引數的型別一致;否則,靜態型別檢查器將引發錯誤。錯誤編寫的 TypeIs 函式可能導致型別系統中的不健全行為;使用者有責任以型別安全的方式編寫此類函式。

如果 TypeIs 函式是類或例項方法,則 TypeIs 中的型別對映到第二個引數的型別(在 clsself 之後)。

簡而言之,形式為 def foo(arg: TypeA) -> TypeIs[TypeB]: ...,意味著如果 foo(arg) 返回 True,則 argTypeB 的一個例項;如果返回 False,則不是 TypeB 的例項。

TypeIs 也適用於型別變數。有關更多資訊,請參閱 PEP 742(使用 TypeIs 縮小型別)。

在 3.13 版本加入。

typing.TypeGuard

用於標記使用者定義的型別謂詞函式的特殊型別構造。

型別謂詞函式是使用者定義的函式,用於返回其引數是否是特定型別的例項。TypeGuard 的工作方式與 TypeIs 類似,但對型別檢查行為有微妙的差異(見下文)。

使用 -> TypeGuard 告訴靜態型別檢查器,對於給定函式

  1. 其返回值是一個布林值。

  2. 如果返回值為 True,則其引數的型別是 TypeGuard 中的型別。

TypeGuard 也適用於型別變數。有關更多詳細資訊,請參閱 PEP 647

例如:

def is_str_list(val: list[object]) -> TypeGuard[list[str]]:
    '''Determines whether all objects in the list are strings'''
    return all(isinstance(x, str) for x in val)

def func1(val: list[object]):
    if is_str_list(val):
        # Type of ``val`` is narrowed to ``list[str]``.
        print(" ".join(val))
    else:
        # Type of ``val`` remains as ``list[object]``.
        print("Not a list of strings!")

TypeIsTypeGuard 的區別如下

  • TypeIs 要求縮小後的型別是輸入型別的子型別,而 TypeGuard 則不要求。主要原因是允許將 list[object] 縮小為 list[str] 之類的情況,儘管後者不是前者的子型別,因為 list 是不變的。

  • TypeGuard 函式返回 True 時,型別檢查器將變數的型別精確地縮小為 TypeGuard 型別。當 TypeIs 函式返回 True 時,型別檢查器可以推斷出更精確的型別,將變數先前已知的型別與 TypeIs 型別結合起來。(從技術上講,這被稱為交集型別。)

  • TypeGuard 函式返回 False 時,型別檢查器根本無法縮小變數的型別。當 TypeIs 函式返回 False 時,型別檢查器可以將變數的型別縮小以排除 TypeIs 型別。

在 3.10 版本加入。

typing.Unpack

型別運算子,用於概念上標記一個物件已被解包。

例如,在 型別變數元組 上使用解包運算子 * 等同於使用 Unpack 將型別變數元組標記為已解包

Ts = TypeVarTuple('Ts')
tup: tuple[*Ts]
# Effectively does:
tup: tuple[Unpack[Ts]]

實際上,在 typing.TypeVarTuplebuiltins.tuple 型別的上下文中,Unpack 可以與 * 互換使用。在較舊的 Python 版本中,你可能會看到 Unpack 被顯式使用,因為 * 無法在某些地方使用

# In older versions of Python, TypeVarTuple and Unpack
# are located in the `typing_extensions` backports package.
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple('Ts')
tup: tuple[*Ts]         # Syntax error on Python <= 3.10!
tup: tuple[Unpack[Ts]]  # Semantically equivalent, and backwards-compatible

Unpack 還可以與 typing.TypedDict 一起用於在函式簽名中為 **kwargs 鍵入型別

from typing import TypedDict, Unpack

class Movie(TypedDict):
    name: str
    year: int

# This function expects two keyword arguments - `name` of type `str`
# and `year` of type `int`.
def foo(**kwargs: Unpack[Movie]): ...

有關使用 Unpack 進行 **kwargs 型別鍵入的更多詳細資訊,請參閱 PEP 692

在 3.11 版本中新增。

構建泛型型別和類型別名

以下類不應直接用作註解。它們旨在作為建立泛型型別和類型別名的構建塊。

這些物件可以透過特殊語法(型別引數列表type 語句)建立。為了與 Python 3.11 及更早版本相容,它們也可以不使用專用語法建立,如下所述。

class typing.Generic

泛型型別的抽象基類。

泛型型別通常透過在類名後新增型別引數列表來宣告

class Mapping[KT, VT]:
    def __getitem__(self, key: KT) -> VT:
        ...
        # Etc.

這樣的類隱式地繼承自 Generic。此語法的執行時語義在 語言參考 中討論。

然後可以如下使用此類

def lookup_name[X, Y](mapping: Mapping[X, Y], key: X, default: Y) -> Y:
    try:
        return mapping[key]
    except KeyError:
        return default

此處函式名後面的括號表示一個 泛型函式

為了向後相容,泛型類也可以透過顯式繼承自 Generic 來宣告。在這種情況下,型別引數必須單獨宣告

KT = TypeVar('KT')
VT = TypeVar('VT')

class Mapping(Generic[KT, VT]):
    def __getitem__(self, key: KT) -> VT:
        ...
        # Etc.
class typing.TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False, default=typing.NoDefault)

型別變數。

構造型別變數的首選方式是透過 泛型函式泛型類泛型類型別名 的專用語法

class Sequence[T]:  # T is a TypeVar
    ...

此語法還可用於建立有界和受約束的型別變數

class StrSequence[S: str]:  # S is a TypeVar with a `str` upper bound;
    ...                     # we can say that S is "bounded by `str`"


class StrOrBytesSequence[A: (str, bytes)]:  # A is a TypeVar constrained to str or bytes
    ...

但是,如果需要,可重用型別變數也可以手動構造,如下所示

T = TypeVar('T')  # Can be anything
S = TypeVar('S', bound=str)  # Can be any subtype of str
A = TypeVar('A', str, bytes)  # Must be exactly str or bytes

型別變數主要用於靜態型別檢查器。它們作為泛型型別以及泛型函式和類型別名定義的引數。有關泛型型別的更多資訊,請參閱 Generic。泛型函式的工作原理如下

def repeat[T](x: T, n: int) -> Sequence[T]:
    """Return a list containing n references to x."""
    return [x]*n


def print_capitalized[S: str](x: S) -> S:
    """Print x capitalized, and return x."""
    print(x.capitalize())
    return x


def concatenate[A: (str, bytes)](x: A, y: A) -> A:
    """Add two strings or bytes objects together."""
    return x + y

請注意,型別變數可以是 *有界的*、*受約束的*,或兩者都不是,但不能同時是有界的 *和* 受約束的。

型別變數的方差由型別檢查器在透過 型別引數語法 建立時,或傳入 infer_variance=True 時推斷。手動建立的型別變數可以透過傳入 covariant=Truecontravariant=True 顯式標記為協變或逆變。預設情況下,手動建立的型別變數是不變的。有關更多詳細資訊,請參閱 PEP 484PEP 695

有界型別變數和受約束型別變數在幾個重要方面具有不同的語義。使用 *有界* 型別變數意味著 TypeVar 將使用最具體的型別求解

x = print_capitalized('a string')
reveal_type(x)  # revealed type is str

class StringSubclass(str):
    pass

y = print_capitalized(StringSubclass('another string'))
reveal_type(y)  # revealed type is StringSubclass

z = print_capitalized(45)  # error: int is not a subtype of str

型別變數的上限可以是具體型別、抽象型別(ABC 或 Protocol),甚至是型別聯合

# Can be anything with an __abs__ method
def print_abs[T: SupportsAbs](arg: T) -> None:
    print("Absolute value:", abs(arg))

U = TypeVar('U', bound=str|bytes)  # Can be any subtype of the union str|bytes
V = TypeVar('V', bound=SupportsAbs)  # Can be anything with an __abs__ method

然而,使用 *受約束* 型別變數意味著 TypeVar 只能被求解為正好是給定約束之一

a = concatenate('one', 'two')
reveal_type(a)  # revealed type is str

b = concatenate(StringSubclass('one'), StringSubclass('two'))
reveal_type(b)  # revealed type is str, despite StringSubclass being passed in

c = concatenate('one', b'two')  # error: type variable 'A' can be either str or bytes in a function call, but not both

在執行時,isinstance(x, T) 將引發 TypeError

__name__

型別變數的名稱。

__covariant__

型別變數是否已顯式標記為協變。

__contravariant__

型別變數是否已顯式標記為逆變。

__infer_variance__

型別檢查器是否應推斷型別變數的方差。

3.12 新版功能.

__bound__

型別變數的上限(如果有)。

3.12 版本中的變化: 對於透過 型別引數語法 建立的型別變數,繫結僅在訪問屬性時進行評估,而不是在建立型別變數時進行評估(請參閱 惰性評估)。

evaluate_bound()

一個 評估函式,對應於 __bound__ 屬性。直接呼叫時,此方法僅支援 VALUE 格式,這等同於直接訪問 __bound__ 屬性,但方法物件可以傳遞給 annotationlib.call_evaluate_function() 以不同格式評估值。

在 3.14 版本加入。

__constraints__

包含型別變數約束的元組(如果有)。

3.12 版本中的變化: 對於透過 型別引數語法 建立的型別變數,約束僅在訪問屬性時進行評估,而不是在建立型別變數時進行評估(請參閱 惰性評估)。

evaluate_constraints()

一個 評估函式,對應於 __constraints__ 屬性。直接呼叫時,此方法僅支援 VALUE 格式,這等同於直接訪問 __constraints__ 屬性,但方法物件可以傳遞給 annotationlib.call_evaluate_function() 以不同格式評估值。

在 3.14 版本加入。

__default__

型別變數的預設值,如果沒有預設值,則為 typing.NoDefault

在 3.13 版本加入。

evaluate_default()

一個 評估函式,對應於 __default__ 屬性。直接呼叫時,此方法僅支援 VALUE 格式,這等同於直接訪問 __default__ 屬性,但方法物件可以傳遞給 annotationlib.call_evaluate_function() 以不同格式評估值。

在 3.14 版本加入。

has_default()

返回型別變數是否具有預設值。這等同於檢查 __default__ 是否不是 typing.NoDefault 單例,只是它不會強制評估 惰性評估 的預設值。

在 3.13 版本加入。

3.12 版本中的變化: 型別變數現在可以使用 PEP 695 引入的 型別引數 語法宣告。infer_variance 引數已新增。

3.13 版本中的變化: 添加了對預設值的支援。

class typing.TypeVarTuple(name, *, default=typing.NoDefault)

型別變數元組。型別變數 的一種特殊形式,支援 *可變引數* 泛型。

型別變數元組可以在 型別引數列表 中使用名稱前的一個星號 (*) 宣告

def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
    return (*tup[1:], tup[0])

或者透過顯式呼叫 TypeVarTuple 建構函式

T = TypeVar("T")
Ts = TypeVarTuple("Ts")

def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
    return (*tup[1:], tup[0])

普通型別變數允許使用單一型別進行引數化。相比之下,型別變數元組透過像元組中包含任意數量的型別變數一樣,允許使用 *任意* 數量的型別進行引數化。例如

# T is bound to int, Ts is bound to ()
# Return value is (1,), which has type tuple[int]
move_first_element_to_last(tup=(1,))

# T is bound to int, Ts is bound to (str,)
# Return value is ('spam', 1), which has type tuple[str, int]
move_first_element_to_last(tup=(1, 'spam'))

# T is bound to int, Ts is bound to (str, float)
# Return value is ('spam', 3.0, 1), which has type tuple[str, float, int]
move_first_element_to_last(tup=(1, 'spam', 3.0))

# This fails to type check (and fails at runtime)
# because tuple[()] is not compatible with tuple[T, *Ts]
# (at least one element is required)
move_first_element_to_last(tup=())

注意 tuple[T, *Ts] 中解包運算子 * 的使用。概念上,你可以將 Ts 視為一個型別變數元組 (T1, T2, ...)tuple[T, *Ts] 將變為 tuple[T, *(T1, T2, ...)],這等同於 tuple[T, T1, T2, ...]。(請注意,在較舊的 Python 版本中,你可能會看到使用 Unpack 來編寫,例如 Unpack[Ts]。)

型別變數元組必須 *始終* 被解包。這有助於將型別變數元組與普通型別變數區分開來

x: Ts          # Not valid
x: tuple[Ts]   # Not valid
x: tuple[*Ts]  # The correct way to do it

型別變數元組可以在與普通型別變數相同的上下文中使用。例如,在類定義、引數和返回型別中

class Array[*Shape]:
    def __getitem__(self, key: tuple[*Shape]) -> float: ...
    def __abs__(self) -> "Array[*Shape]": ...
    def get_shape(self) -> tuple[*Shape]: ...

型別變數元組可以與普通型別變數很好地結合使用

class Array[DType, *Shape]:  # This is fine
    pass

class Array2[*Shape, DType]:  # This would also be fine
    pass

class Height: ...
class Width: ...

float_array_1d: Array[float, Height] = Array()     # Totally fine
int_array_2d: Array[int, Height, Width] = Array()  # Yup, fine too

但是,請注意,在單個型別引數列表或型別引數列表中最多隻能出現一個型別變數元組

x: tuple[*Ts, *Ts]            # Not valid
class Array[*Shape, *Shape]:  # Not valid
    pass

最後,解包的型別變數元組可以用作 *args 的型別註解

def call_soon[*Ts](
    callback: Callable[[*Ts], None],
    *args: *Ts
) -> None:
    ...
    callback(*args)

*args 的未解包註解(例如 *args: int,這將指定 *所有* 引數都是 int)相反,*args: *Ts 允許引用 *args 中 *單個* 引數的型別。在這裡,這允許我們確保傳遞給 call_soon*args 的型別與 callback 的(位置)引數的型別匹配。

有關型別變數元組的更多詳細資訊,請參閱 PEP 646

__name__

型別變數元組的名稱。

__default__

型別變數元組的預設值,如果沒有預設值,則為 typing.NoDefault

在 3.13 版本加入。

evaluate_default()

一個 評估函式,對應於 __default__ 屬性。直接呼叫時,此方法僅支援 VALUE 格式,這等同於直接訪問 __default__ 屬性,但方法物件可以傳遞給 annotationlib.call_evaluate_function() 以不同格式評估值。

在 3.14 版本加入。

has_default()

返回型別變數元組是否具有預設值。這等同於檢查 __default__ 是否不是 typing.NoDefault 單例,只是它不會強制評估 惰性評估 的預設值。

在 3.13 版本加入。

在 3.11 版本中新增。

3.12 版本中的變化: 型別變數元組現在可以使用 PEP 695 引入的 型別引數 語法宣告。

3.13 版本中的變化: 添加了對預設值的支援。

class typing.ParamSpec(name, *, bound=None, covariant=False, contravariant=False, default=typing.NoDefault)

引數規範變數。型別變數 的一種特殊版本。

型別引數列表 中,引數規範可以用兩個星號 (**) 宣告

type IntFunc[**P] = Callable[P, int]

為了與 Python 3.11 及更早版本相容,ParamSpec 物件也可以按如下方式建立

P = ParamSpec('P')

引數規範變數主要用於靜態型別檢查器。它們用於將一個可呼叫物件的引數型別轉發到另一個可呼叫物件——這種模式常見於高階函式和裝飾器中。它們僅在 Concatenate 中,或作為 Callable 的第一個引數,或作為使用者定義泛型的引數時有效。有關泛型型別的更多資訊,請參閱 Generic

例如,要為函式新增基本日誌記錄,可以建立一個裝飾器 add_logging 來記錄函式呼叫。引數規範變數告訴型別檢查器,傳入裝飾器的可呼叫物件和它返回的新可呼叫物件具有相互依賴的型別引數

from collections.abc import Callable
import logging

def add_logging[T, **P](f: Callable[P, T]) -> Callable[P, T]:
    '''A type-safe decorator to add logging to a function.'''
    def inner(*args: P.args, **kwargs: P.kwargs) -> T:
        logging.info(f'{f.__name__} was called')
        return f(*args, **kwargs)
    return inner

@add_logging
def add_two(x: float, y: float) -> float:
    '''Add two numbers together.'''
    return x + y

如果沒有 ParamSpec,之前標註此函式的最簡單方法是使用一個上限為 Callable[..., Any]TypeVar。但這會導致兩個問題

  1. 型別檢查器無法型別檢查 inner 函式,因為 *args**kwargs 必須被型別化為 Any

  2. 在返回 inner 函式時,可能需要在 add_logging 裝飾器的主體中使用 cast(),或者必須告知靜態型別檢查器忽略 return inner

args
kwargs

由於 ParamSpec 捕獲位置引數和關鍵字引數,因此可以使用 P.argsP.kwargsParamSpec 拆分為其元件。P.args 表示給定呼叫中的位置引數元組,並且應僅用於註解 *argsP.kwargs 表示給定呼叫中關鍵字引數到其值的對映,並且應僅用於註解 **kwargs。這兩個屬性都要求註解的引數在作用域內。在執行時,P.argsP.kwargs 分別是 ParamSpecArgsParamSpecKwargs 的例項。

__name__

引數規範的名稱。

__default__

引數規範的預設值,如果沒有預設值,則為 typing.NoDefault

在 3.13 版本加入。

evaluate_default()

一個 評估函式,對應於 __default__ 屬性。直接呼叫時,此方法僅支援 VALUE 格式,這等同於直接訪問 __default__ 屬性,但方法物件可以傳遞給 annotationlib.call_evaluate_function() 以不同格式評估值。

在 3.14 版本加入。

has_default()

返回引數規範是否具有預設值。這等同於檢查 __default__ 是否不是 typing.NoDefault 單例,只是它不會強制評估 惰性評估 的預設值。

在 3.13 版本加入。

使用 covariant=Truecontravariant=True 建立的引數規範變數可用於宣告協變或逆變泛型型別。bound 引數也接受,類似於 TypeVar。但是,這些關鍵字的實際語義尚待確定。

在 3.10 版本加入。

3.12 版本中的變化: 引數規範現在可以使用 PEP 695 引入的 型別引數 語法宣告。

3.13 版本中的變化: 添加了對預設值的支援。

備註

只有在全域性作用域中定義的引數規範變數才能被 pickle。

參見

typing.ParamSpecArgs
typing.ParamSpecKwargs

ParamSpec 的引數和關鍵字引數屬性。ParamSpecP.args 屬性是 ParamSpecArgs 的例項,而 P.kwargsParamSpecKwargs 的例項。它們旨在用於執行時內省,對靜態型別檢查器沒有特殊含義。

對這些物件中的任何一個呼叫 get_origin() 將返回原始的 ParamSpec

>>> from typing import ParamSpec, get_origin
>>> P = ParamSpec("P")
>>> get_origin(P.args) is P
True
>>> get_origin(P.kwargs) is P
True

在 3.10 版本加入。

class typing.TypeAliasType(name, value, *, type_params=())

透過 type 語句建立的類型別名的型別。

示例

>>> type Alias = int
>>> type(Alias)
<class 'typing.TypeAliasType'>

3.12 新版功能.

__name__

類型別名的名稱

>>> type Alias = int
>>> Alias.__name__
'Alias'
__module__

定義類型別名的模組名稱

>>> type Alias = int
>>> Alias.__module__
'__main__'
__type_params__

類型別名的型別引數,如果別名不是泛型的,則為空元組

>>> type ListOrSet[T] = list[T] | set[T]
>>> ListOrSet.__type_params__
(T,)
>>> type NotGeneric = int
>>> NotGeneric.__type_params__
()
__value__

類型別名的值。這是 惰性評估 的,因此別名定義中使用的名稱直到訪問 __value__ 屬性時才會被解析

>>> type Mutually = Recursive
>>> type Recursive = Mutually
>>> Mutually
Mutually
>>> Recursive
Recursive
>>> Mutually.__value__
Recursive
>>> Recursive.__value__
Mutually
evaluate_value()

一個 評估函式,對應於 __value__ 屬性。直接呼叫時,此方法僅支援 VALUE 格式,這等同於直接訪問 __value__ 屬性,但方法物件可以傳遞給 annotationlib.call_evaluate_function() 以不同格式評估值

>>> type Alias = undefined
>>> Alias.__value__
Traceback (most recent call last):
...
NameError: name 'undefined' is not defined
>>> from annotationlib import Format, call_evaluate_function
>>> Alias.evaluate_value(Format.VALUE)
Traceback (most recent call last):
...
NameError: name 'undefined' is not defined
>>> call_evaluate_function(Alias.evaluate_value, Format.FORWARDREF)
ForwardRef('undefined')

在 3.14 版本加入。

解包

類型別名支援使用 *Alias 語法進行星號解包。這等同於直接使用 Unpack[Alias]

>>> type Alias = tuple[int, str]
>>> type Unpacked = tuple[bool, *Alias]
>>> Unpacked.__value__
tuple[bool, typing.Unpack[Alias]]

在 3.14 版本加入。

其他特殊指令

這些函式和類不應直接用作註解。它們旨在作為建立和宣告型別的構建塊。

class typing.NamedTuple

collections.namedtuple() 的帶型別版本。

用法

class Employee(NamedTuple):
    name: str
    id: int

這等價於:

Employee = collections.namedtuple('Employee', ['name', 'id'])

要為欄位提供預設值,可以在類主體中為其賦值

class Employee(NamedTuple):
    name: str
    id: int = 3

employee = Employee('Guido')
assert employee.id == 3

具有預設值的欄位必須位於任何沒有預設值的欄位之後。

生成的類有一個額外的屬性 __annotations__,它給出了一個將欄位名稱對映到欄位型別的字典。(欄位名稱在 _fields 屬性中,預設值在 _field_defaults 屬性中,這兩個屬性都是 namedtuple() API 的一部分。)

NamedTuple 子類還可以有文件字串和方法

class Employee(NamedTuple):
    """Represents an employee."""
    name: str
    id: int = 3

    def __repr__(self) -> str:
        return f'<Employee {self.name}, id={self.id}>'

NamedTuple 子類可以是泛型的

class Group[T](NamedTuple):
    key: T
    group: list[T]

向後相容用法

# For creating a generic NamedTuple on Python 3.11
T = TypeVar("T")

class Group(NamedTuple, Generic[T]):
    key: T
    group: list[T]

# A functional syntax is also supported
Employee = NamedTuple('Employee', [('name', str), ('id', int)])

3.6 版本中的變化: 添加了對 PEP 526 變數註解語法的支援。

3.6.1 版本中的變化: 添加了對預設值、方法和文件字串的支援。

3.8 版本中的變化: _field_types__annotations__ 屬性現在是普通字典而不是 OrderedDict 的例項。

3.9 版本中的變化: 刪除了 _field_types 屬性,取而代之的是更標準的 __annotations__ 屬性,它包含相同的資訊。

3.11 版本中的變化: 添加了對泛型命名元組的支援。

3.14 版本中的變化: NamedTuple 子類的方法中使用 super()(以及 __class__ 閉包變數)是不受支援的,並會導致 TypeError

自 3.13 版棄用,將在 3.15 版中移除: 用於建立 NamedTuple 類的未文件關鍵字引數語法 (NT = NamedTuple("NT", x=int)) 已棄用,並將在 3.15 中停用。請改用基於類或函式式語法。

自 3.13 版棄用,將在 3.15 版中移除: 在使用函式式語法建立 NamedTuple 類時,未向“fields”引數傳遞值 (NT = NamedTuple("NT")) 已棄用。向“fields”引數傳遞 None (NT = NamedTuple("NT", None)) 也已棄用。兩者都將在 Python 3.15 中停用。要建立具有 0 個欄位的 NamedTuple 類,請使用 class NT(NamedTuple): passNT = NamedTuple("NT", [])

class typing.NewType(name, tp)

用於建立低開銷 不同型別 的輔助類。

NewType 被型別檢查器視為一種不同的型別。然而,在執行時,呼叫 NewType 會返回其引數不變。

用法

UserId = NewType('UserId', int)  # Declare the NewType "UserId"
first_user = UserId(1)  # "UserId" returns the argument unchanged at runtime
__module__

定義新型別的模組的名稱。

__name__

新型別的名稱。

__supertype__

新型別所基於的型別。

3.5.2 版本新增。

3.10 版本中的變化: NewType 現在是一個類而不是一個函式。

class typing.Protocol(Generic)

協議類的基類。

協議類定義如下

class Proto(Protocol):
    def meth(self) -> int:
        ...

此類主要與識別結構子型別(靜態鴨子型別)的靜態型別檢查器一起使用,例如

class C:
    def meth(self) -> int:
        return 0

def func(x: Proto) -> int:
    return x.meth()

func(C())  # Passes static type check

有關更多詳細資訊,請參閱 PEP 544。用 runtime_checkable()(稍後描述)裝飾的協議類充當簡單的執行時協議,僅檢查給定屬性的存在,而忽略其型別簽名。沒有此裝飾器的協議類不能用作 isinstance()issubclass() 的第二個引數。

協議類可以是泛型的,例如

class GenProto[T](Protocol):
    def meth(self) -> T:
        ...

在需要與 Python 3.11 或更早版本相容的程式碼中,泛型協議可以按如下方式編寫

T = TypeVar("T")

class GenProto(Protocol[T]):
    def meth(self) -> T:
        ...

在 3.8 版本加入。

@typing.runtime_checkable

將協議類標記為執行時協議。

此協議可與 isinstance()issubclass() 一起使用。這允許進行簡單的結構檢查,這與 collections.abc 中的“一招鮮”類似,例如 Iterable。例如

@runtime_checkable
class Closable(Protocol):
    def close(self): ...

assert isinstance(open('/some/file'), Closable)

@runtime_checkable
class Named(Protocol):
    name: str

import threading
assert isinstance(threading.Thread(name='Bob'), Named)

當應用於非協議類時,此裝飾器會引發 TypeError

備註

runtime_checkable() 將僅檢查所需方法或屬性的存在,而不檢查它們的型別簽名或型別。例如,ssl.SSLObject 是一個類,因此它通過了 issubclass()Callable 的檢查。但是,ssl.SSLObject.__init__ 方法僅用於引發帶有更具資訊性訊息的 TypeError,因此無法呼叫(例項化)ssl.SSLObject

備註

與對非協議類的 isinstance() 檢查相比,對執行時可檢查協議的 isinstance() 檢查可能會出乎意料地慢。在效能敏感的程式碼中,請考慮使用 hasattr() 呼叫等替代方案進行結構檢查。

在 3.8 版本加入。

3.12 版本中的變化: 針對執行時可檢查協議的 isinstance() 檢查的內部實現現在使用 inspect.getattr_static() 來查詢屬性(以前使用 hasattr())。因此,在 Python 3.12+ 上,某些過去被認為是執行時可檢查協議例項的物件可能不再被認為是該協議的例項,反之亦然。大多數使用者不太可能受到此更改的影響。

3.12 版本中的變化: 執行時可檢查協議的成員現在在類建立後立即在執行時被視為“凍結”。修補執行時可檢查協議的屬性仍然有效,但不會對比較物件與協議的 isinstance() 檢查產生影響。有關更多詳細資訊,請參閱 Python 3.12 中的新特性

class typing.TypedDict(dict)

用於為字典新增型別提示的特殊構造。在執行時,它是一個普通的 dict

TypedDict 聲明瞭一個字典型別,它期望其所有例項都具有一組特定的鍵,其中每個鍵都與一致型別的值相關聯。這種期望在執行時不會被檢查,僅由型別檢查器強制執行。用法

class Point2D(TypedDict):
    x: int
    y: int
    label: str

a: Point2D = {'x': 1, 'y': 2, 'label': 'good'}  # OK
b: Point2D = {'z': 3, 'label': 'bad'}           # Fails type check

assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')

建立 TypedDict 的另一種方法是使用函式呼叫語法。第二個引數必須是一個字面 dict

Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})

此函式式語法允許定義非有效 識別符號 的鍵,例如因為它們是關鍵字或包含連字元,或者當鍵名不能像常規私有名稱一樣被 損壞

# raises SyntaxError
class Point2D(TypedDict):
    in: int  # 'in' is a keyword
    x-y: int  # name with hyphens

class Definition(TypedDict):
    __schema: str  # mangled to `_Definition__schema`

# OK, functional syntax
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
Definition = TypedDict('Definition', {'__schema': str})  # not mangled

預設情況下,所有鍵都必須存在於 TypedDict 中。可以使用 NotRequired 將單個鍵標記為非必需

class Point2D(TypedDict):
    x: int
    y: int
    label: NotRequired[str]

# Alternative syntax
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': NotRequired[str]})

這意味著 Point2D TypedDict 可以省略 label 鍵。

也可以透過指定 False 的總量來預設將所有鍵標記為非必需

class Point2D(TypedDict, total=False):
    x: int
    y: int

# Alternative syntax
Point2D = TypedDict('Point2D', {'x': int, 'y': int}, total=False)

這意味著 Point2D TypedDict 可以省略任何鍵。型別檢查器僅期望支援字面值 FalseTrue 作為 total 引數的值。True 是預設值,並使類主體中定義的所有項成為必需項。

total=False TypedDict 的單個鍵可以使用 Required 標記為必需

class Point2D(TypedDict, total=False):
    x: Required[int]
    y: Required[int]
    label: str

# Alternative syntax
Point2D = TypedDict('Point2D', {
    'x': Required[int],
    'y': Required[int],
    'label': str
}, total=False)

TypedDict 型別可以使用基於類的語法繼承一個或多個其他 TypedDict 型別。用法

class Point3D(Point2D):
    z: int

Point3D 有三個項:xyz。這等同於此定義

class Point3D(TypedDict):
    x: int
    y: int
    z: int

一個 TypedDict 不能從非 TypedDict 類繼承,除了 Generic。例如

class X(TypedDict):
    x: int

class Y(TypedDict):
    y: int

class Z(object): pass  # A non-TypedDict class

class XY(X, Y): pass  # OK

class XZ(X, Z): pass  # raises TypeError

一個 TypedDict 可以是泛型的

class Group[T](TypedDict):
    key: T
    group: list[T]

要建立與 Python 3.11 或更低版本相容的泛型 TypedDict,請顯式繼承自 Generic

T = TypeVar("T")

class Group(TypedDict, Generic[T]):
    key: T
    group: list[T]

TypedDict 可以透過註解字典(有關注解最佳實踐的更多資訊,請參閱 註解最佳實踐)、__total____required_keys____optional_keys__ 進行內省。

__total__

Point2D.__total__ 給出 total 引數的值。示例

>>> from typing import TypedDict
>>> class Point2D(TypedDict): pass
>>> Point2D.__total__
True
>>> class Point2D(TypedDict, total=False): pass
>>> Point2D.__total__
False
>>> class Point3D(Point2D): pass
>>> Point3D.__total__
True

此屬性 *僅* 反映當前 TypedDict 類的 total 引數值,而不是該類是否在語義上是完整的。例如,一個 __total__ 設定為 TrueTypedDict 可能具有用 NotRequired 標記的鍵,或者它可能繼承自另一個 TypedDict,其 total=False。因此,通常最好使用 __required_keys____optional_keys__ 進行內省。

__required_keys__

在 3.9 版本中新增。

__optional_keys__

Point2D.__required_keys__Point2D.__optional_keys__ 分別返回包含必需鍵和非必需鍵的 frozenset 物件。

標記為 Required 的鍵將始終出現在 __required_keys__ 中,標記為 NotRequired 的鍵將始終出現在 __optional_keys__ 中。

為了向後相容 Python 3.10 及更早版本,還可以使用繼承在同一個 TypedDict 中同時宣告必需鍵和非必需鍵。這透過宣告一個 TypedDict,其 total 引數有一個值,然後在其另一個 TypedDict 中繼承它,該 TypedDicttotal 具有不同的值

>>> class Point2D(TypedDict, total=False):
...     x: int
...     y: int
...
>>> class Point3D(Point2D):
...     z: int
...
>>> Point3D.__required_keys__ == frozenset({'z'})
True
>>> Point3D.__optional_keys__ == frozenset({'x', 'y'})
True

在 3.9 版本中新增。

備註

如果使用 from __future__ import annotations 或將註解作為字串提供,則在定義 TypedDict 時不會評估註解。因此,__required_keys____optional_keys__ 依賴的執行時內省可能無法正常工作,並且屬性值可能不正確。

ReadOnly 的支援反映在以下屬性中

__readonly_keys__

一個 frozenset,包含所有隻讀鍵的名稱。如果鍵帶有 ReadOnly 限定符,則它們是隻讀的。

在 3.13 版本加入。

__mutable_keys__

一個 frozenset,包含所有可變鍵的名稱。如果鍵不帶有 ReadOnly 限定符,則它們是可變的。

在 3.13 版本加入。

有關更多示例和詳細規則,請參閱型別文件中的 TypedDict 部分。

在 3.8 版本加入。

3.11 版本中的變化: 添加了對將單個鍵標記為 RequiredNotRequired 的支援。請參閱 PEP 655

版本 3.11 中的變化: 添加了對泛型 TypedDict 的支援。

版本 3.13 中的變化: 移除了透過關鍵字引數方法建立 TypedDict 的支援。

版本 3.13 中的變化: 添加了對 ReadOnly 限定符的支援。

自 3.13 版本棄用,將在 3.15 版本中移除: 當使用函式式語法建立 TypedDict 類時,未能向 'fields' 引數傳遞值 (TD = TypedDict("TD")) 已被棄用。向 'fields' 引數傳遞 None (TD = TypedDict("TD", None)) 也已被棄用。兩者都將在 Python 3.15 中被禁止。要建立一個包含 0 個欄位的 TypedDict 類,請使用 class TD(TypedDict): passTD = TypedDict("TD", {})

協議

typing 模組提供了以下協議。所有協議都用 @runtime_checkable 裝飾。

class typing.SupportsAbs

一個 ABC,帶有一個抽象方法 __abs__,其返回型別是協變的。

class typing.SupportsBytes

一個 ABC,帶有一個抽象方法 __bytes__

class typing.SupportsComplex

一個 ABC,帶有一個抽象方法 __complex__

class typing.SupportsFloat

一個 ABC,帶有一個抽象方法 __float__

class typing.SupportsIndex

一個 ABC,帶有一個抽象方法 __index__

在 3.8 版本加入。

class typing.SupportsInt

一個 ABC,帶有一個抽象方法 __int__

class typing.SupportsRound

一個 ABC,帶有一個抽象方法 __round__,其返回型別是協變的。

用於處理 I/O 的 ABC 和協議

class typing.IO[AnyStr]
class typing.TextIO[AnyStr]
class typing.BinaryIO[AnyStr]

泛型類 IO[AnyStr] 及其子類 TextIO(IO[str])BinaryIO(IO[bytes]) 表示 I/O 流的型別,例如由 open() 返回的流。請注意,這些類不是協議,它們的介面相當廣泛。

協議 io.Readerio.Writer 為引數型別提供了更簡單的替代方案,分別僅在訪問 read()write() 方法時使用

def read_and_write(reader: Reader[str], writer: Writer[bytes]):
    data = reader.read()
    writer.write(data.encode())

還可以考慮使用 collections.abc.Iterable 來迭代輸入流的行

def read_config(stream: Iterable[str]):
    for line in stream:
        ...

函式和裝飾器

typing.cast(typ, val)

將值強制轉換為某種型別。

這會原樣返回該值。對於型別檢查器來說,這表示返回值具有指定的型別,但在執行時我們有意不檢查任何內容(我們希望它儘可能快)。

typing.assert_type(val, typ, /)

要求靜態型別檢查器確認 val 的推斷型別為 typ

在執行時,這不做任何事情:它返回第一個引數不變,沒有檢查或副作用,無論引數的實際型別是什麼。

當靜態型別檢查器遇到對 assert_type() 的呼叫時,如果值不是指定型別,它會發出錯誤

def greet(name: str) -> None:
    assert_type(name, str)  # OK, inferred type of `name` is `str`
    assert_type(name, int)  # type checker error

此函式有助於確保型別檢查器對指令碼的理解與開發者的意圖一致

def complex_function(arg: object):
    # Do some complex type-narrowing logic,
    # after which we hope the inferred type will be `int`
    ...
    # Test whether the type checker correctly understands our function
    assert_type(arg, int)

在 3.11 版本中新增。

typing.assert_never(arg, /)

要求靜態型別檢查器確認某行程式碼無法訪問。

示例

def int_or_str(arg: int | str) -> None:
    match arg:
        case int():
            print("It's an int")
        case str():
            print("It's a str")
        case _ as unreachable:
            assert_never(unreachable)

在這裡,註解允許型別檢查器推斷出最後一個 case 永遠不會執行,因為 arg 要麼是 int 要麼是 str,並且這兩個選項都被前面的 case 覆蓋了。

如果型別檢查器發現對 assert_never() 的呼叫是可達的,它將發出錯誤。例如,如果 arg 的型別註解是 int | str | float,則型別檢查器將發出錯誤,指出 unreachable 的型別是 float。要使對 assert_never 的呼叫透過型別檢查,傳入引數的推斷型別必須是底部型別 Never,而不是其他任何型別。

在執行時,當呼叫此函式時會引發異常。

參見

不可達程式碼和窮盡性檢查 提供了有關使用靜態型別進行窮盡性檢查的更多資訊。

在 3.11 版本中新增。

typing.reveal_type(obj, /)

要求靜態型別檢查器顯示錶達式的推斷型別。

當靜態型別檢查器遇到對此函式的呼叫時,它會發出一個帶有引數推斷型別的診斷。例如

x: int = 1
reveal_type(x)  # Revealed type is "builtins.int"

當您想除錯型別檢查器如何處理特定程式碼時,這會很有用。

在執行時,此函式將其引數的執行時型別列印到 sys.stderr 並原樣返回引數(允許在表示式中使用該呼叫)

x = reveal_type(1)  # prints "Runtime type is int"
print(x)  # prints "1"

請注意,執行時型別可能與(更具體或不那麼具體於)型別檢查器靜態推斷的型別不同。

大多數型別檢查器都支援在任何地方使用 reveal_type(),即使該名稱沒有從 typing 匯入。然而,從 typing 匯入該名稱可以使您的程式碼在執行時不會出現錯誤,並更清楚地傳達意圖。

在 3.11 版本中新增。

@typing.dataclass_transform(*, eq_default=True, order_default=False, kw_only_default=False, frozen_default=False, field_specifiers=(), **kwargs)

標記物件提供 dataclass-like 行為的裝飾器。

dataclass_transform 可用於裝飾類、元類或本身是裝飾器的函式。@dataclass_transform() 的存在告訴靜態型別檢查器,被裝飾物件執行執行時“魔術”,以類似於 @dataclasses.dataclass 的方式轉換類。

裝飾器函式的使用示例

@dataclass_transform()
def create_model[T](cls: type[T]) -> type[T]:
    ...
    return cls

@create_model
class CustomerModel:
    id: int
    name: str

在基類上

@dataclass_transform()
class ModelBase: ...

class CustomerModel(ModelBase):
    id: int
    name: str

在元類上

@dataclass_transform()
class ModelMeta(type): ...

class ModelBase(metaclass=ModelMeta): ...

class CustomerModel(ModelBase):
    id: int
    name: str

上面定義的 CustomerModel 類將被型別檢查器處理,類似於使用 @dataclasses.dataclass 建立的類。例如,型別檢查器將假定這些類具有接受 idname__init__ 方法。

被裝飾的類、元類或函式可以接受以下布林引數,型別檢查器將假定它們具有與 @dataclasses.dataclass 裝飾器相同的效果:initeqorderunsafe_hashfrozenmatch_argskw_onlyslots。這些引數的值(TrueFalse)必須能夠被靜態評估。

dataclass_transform 裝飾器的引數可用於自定義被裝飾類、元類或函式的預設行為

引數:
  • eq_default (bool) – 指示如果呼叫者省略 eq 引數,則其值應假定為 True 還是 False。預設為 True

  • order_default (bool) – 指示如果呼叫者省略 order 引數,則其值應假定為 True 還是 False。預設為 False

  • kw_only_default (bool) – 指示如果呼叫者省略 kw_only 引數,則其值應假定為 True 還是 False。預設為 False

  • frozen_default (bool) –

    指示如果呼叫者省略 frozen 引數,則其值應假定為 True 還是 False。預設為 False

    3.12 新版功能.

  • field_specifiers (tuple[Callable[..., Any], ...]) – 指定支援的類或函式的靜態列表,用於描述欄位,類似於 dataclasses.field()。預設為 ()

  • **kwargs (Any) – 接受任意其他關鍵字引數,以允許可能的未來擴充套件。

型別檢查器識別字段說明符上的以下可選引數

欄位說明符的識別引數

引數名稱

描述

init

指示欄位是否應包含在合成的 __init__ 方法中。如果未指定,init 預設為 True

default

提供欄位的預設值。

default_factory

提供一個執行時回撥,返回欄位的預設值。如果 defaultdefault_factory 均未指定,則假定該欄位沒有預設值,並且在例項化類時必須提供一個值。

factory

欄位說明符上 default_factory 引數的別名。

kw_only

指示欄位是否應標記為僅限關鍵字引數。如果為 True,則該欄位將為僅限關鍵字引數。如果為 False,則它將不是僅限關鍵字引數。如果未指定,則使用用 dataclass_transform 裝飾的物件上的 kw_only 引數的值,或者如果該引數未指定,則使用 dataclass_transform 上的 kw_only_default 值。

alias

為欄位提供一個替代名稱。此替代名稱用於合成的 __init__ 方法。

在執行時,此裝飾器將其引數記錄在被裝飾物件的 __dataclass_transform__ 屬性中。它沒有其他執行時效果。

有關更多詳細資訊,請參閱 PEP 681

在 3.11 版本中新增。

@typing.overload

用於建立過載函式和方法的裝飾器。

@overload 裝飾器允許描述支援多種不同引數型別組合的函式和方法。一系列 @overload 裝飾的定義之後必須緊跟一個未被 @overload 裝飾的定義(針對同一個函式/方法)。

@overload 裝飾的定義僅用於型別檢查器,因為它們將被非 @overload 裝飾的定義覆蓋。同時,非 @overload 裝飾的定義將在執行時使用,但應被型別檢查器忽略。在執行時,直接呼叫 @overload 裝飾的函式將引發 NotImplementedError

一個過載示例,它提供了比使用 union 或型別變量表達更精確的型別

@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    ...  # actual implementation goes here

有關更多詳細資訊以及與其他型別語義的比較,請參閱 PEP 484

版本 3.11 中的變化: 現在可以使用 get_overloads() 在執行時內省過載函式。

typing.get_overloads(func)

返回 func@overload 裝飾定義序列。

func 是過載函式實現的函式物件。例如,給定 @overload 文件中的 process 定義,get_overloads(process) 將返回三個已定義過載的三個函式物件序列。如果對沒有過載的函式呼叫,get_overloads() 返回一個空序列。

get_overloads() 可用於在執行時內省過載函式。

在 3.11 版本中新增。

typing.clear_overloads()

清除內部登錄檔中的所有已註冊過載。

這可用於回收登錄檔使用的記憶體。

在 3.11 版本中新增。

@typing.final

指示最終方法和最終類的裝飾器。

使用 @final 裝飾方法向型別檢查器指示該方法不能在子類中被覆蓋。使用 @final 裝飾類指示它不能被子類化。

例如:

class Base:
    @final
    def done(self) -> None:
        ...
class Sub(Base):
    def done(self) -> None:  # Error reported by type checker
        ...

@final
class Leaf:
    ...
class Other(Leaf):  # Error reported by type checker
    ...

這些屬性沒有執行時檢查。有關更多詳細資訊,請參閱 PEP 591

在 3.8 版本加入。

版本 3.11 中的變化: 裝飾器現在將嘗試在被裝飾物件上將 __final__ 屬性設定為 True。因此,在執行時可以使用諸如 if getattr(obj, "__final__", False) 這樣的檢查來確定物件 obj 是否已被標記為 final。如果被裝飾物件不支援設定屬性,則裝飾器將返回未更改的物件,而不引發異常。

@typing.no_type_check

指示註解不是型別提示的裝飾器。

這作為類或函式 裝飾器 起作用。對於類,它遞迴地應用於該類中定義的所有方法和類(但不適用於其超類或子類中定義的方法)。型別檢查器將忽略帶有此裝飾器的函式或類中的所有註解。

@no_type_check 會就地修改被裝飾物件。

@typing.no_type_check_decorator

一個裝飾器,用於賦予另一個裝飾器 no_type_check() 效果。

這會將裝飾器封裝在一個東西中,該東西又將裝飾的函式封裝在 no_type_check() 中。

自 3.13 版本棄用,將在 3.15 版本中移除: 沒有任何型別檢查器曾新增對 @no_type_check_decorator 的支援。因此,它已被棄用,並將在 Python 3.15 中移除。

@typing.override

指示子類中的方法旨在覆蓋超類中的方法或屬性的裝飾器。

型別檢查器應在用 @override 裝飾的方法實際上沒有覆蓋任何內容時發出錯誤。這有助於防止在更改基類而子類沒有相應更改時可能發生的錯誤。

例如:

class Base:
    def log_status(self) -> None:
        ...

class Sub(Base):
    @override
    def log_status(self) -> None:  # Okay: overrides Base.log_status
        ...

    @override
    def done(self) -> None:  # Error reported by type checker
        ...

此屬性沒有執行時檢查。

裝飾器將嘗試在被裝飾物件上將 __override__ 屬性設定為 True。因此,可以在執行時使用諸如 if getattr(obj, "__override__", False) 的檢查來確定物件 obj 是否已被標記為覆蓋。如果被裝飾物件不支援設定屬性,裝飾器將返回未更改的物件而不引發異常。

有關更多詳細資訊,請參閱 PEP 698

3.12 新版功能.

@typing.type_check_only

標記類或函式在執行時不可用的裝飾器。

這個裝飾器本身在執行時不可用。它主要用於標記在型別存根檔案中定義的類,如果實現返回私有類的例項

@type_check_only
class Response:  # private or not available at runtime
    code: int
    def get_header(self, name: str) -> str: ...

def fetch_response() -> Response: ...

請注意,不建議返回私有類的例項。通常更傾向於將此類類公開。

內省助手

typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False)

返回包含函式、方法、模組或類物件的型別提示的字典。

這通常與 obj.__annotations__ 相同,但此函式對註解字典進行以下更改

  • 透過在 globalnslocalns 以及(適用時)objtype parameter 名稱空間中評估,處理編碼為字串字面量或 ForwardRef 物件的正向引用。如果未給出 globalnslocalns,則從 obj 推斷適當的名稱空間字典。

  • None 被替換為 types.NoneType

  • 如果 @no_type_check 已應用於 obj,則返回一個空字典。

  • 如果 obj 是類 C,則該函式返回一個字典,該字典將 C 的基類中的註解與 C 上直接的註解合併。這是透過遍歷 C.__mro__ 並迭代組合 __annotations__ 字典來完成的。在 方法解析順序 中較早出現的類上的註解總是優先於在方法解析順序中較晚出現的類上的註解。

  • 該函式遞迴地將所有 Annotated[T, ...] 的出現替換為 T,除非 include_extras 設定為 True(有關更多資訊,請參閱 Annotated)。

另請參閱 annotationlib.get_annotations(),這是一個更底層的函式,它更直接地返回註解。

注意

此函式可能會執行註解中包含的任意程式碼。有關更多資訊,請參閱 內省註解的安全影響

備註

如果 obj 的註解中的任何前向引用無法解析或不是有效的 Python 程式碼,此函式將引發異常,例如 NameError。例如,這可能發生在包含前向引用的匯入 類型別名 或在 if TYPE_CHECKING 下匯入的名稱。

版本 3.9 中的變化: 作為 PEP 593 的一部分,添加了 include_extras 引數。有關更多資訊,請參閱 Annotated 的文件。

版本 3.11 中的變化: 以前,如果設定了等於 None 的預設值,則會為函式和方法註解新增 Optional[t]。現在,註解原樣返回。

typing.get_origin(tp)

獲取型別的未下標版本:對於 X[Y, Z, ...] 形式的 typing 物件,返回 X

如果 X 是內建類或 collections 類的 typing 模組別名,它將被規範化為原始類。如果 XParamSpecArgsParamSpecKwargs 的例項,則返回底層 ParamSpec。對於不支援的物件,返回 None

示例:

assert get_origin(str) is None
assert get_origin(Dict[str, int]) is dict
assert get_origin(Union[int, str]) is Union
assert get_origin(Annotated[str, "metadata"]) is Annotated
P = ParamSpec('P')
assert get_origin(P.args) is P
assert get_origin(P.kwargs) is P

在 3.8 版本加入。

typing.get_args(tp)

獲取所有替換已執行的型別引數:對於 X[Y, Z, ...] 形式的 typing 物件,返回 (Y, Z, ...)

如果 X 是包含在另一個泛型型別中的 union 或 Literal,則 (Y, Z, ...) 的順序可能與原始引數 [Y, Z, ...] 的順序不同,這是由於型別快取。對於不支援的物件,返回 ()

示例:

assert get_args(int) == ()
assert get_args(Dict[int, str]) == (int, str)
assert get_args(Union[int, str]) == (int, str)

在 3.8 版本加入。

typing.get_protocol_members(tp)

返回 Protocol 中定義的成員集合。

>>> from typing import Protocol, get_protocol_members
>>> class P(Protocol):
...     def a(self) -> str: ...
...     b: int
>>> get_protocol_members(P) == frozenset({'a', 'b'})
True

對於不是協議的引數,引發 TypeError

在 3.13 版本加入。

typing.is_protocol(tp)

判斷一個型別是否為 Protocol

例如:

class P(Protocol):
    def a(self) -> str: ...
    b: int

is_protocol(P)    # => True
is_protocol(int)  # => False

在 3.13 版本加入。

typing.is_typeddict(tp)

檢查一個型別是否為 TypedDict

例如:

class Film(TypedDict):
    title: str
    year: int

assert is_typeddict(Film)
assert not is_typeddict(list | str)

# TypedDict is a factory for creating typed dicts,
# not a typed dict itself
assert not is_typeddict(TypedDict)

在 3.10 版本加入。

class typing.ForwardRef

用於字串前向引用的內部型別表示的類。

例如,List["SomeClass"] 被隱式轉換為 List[ForwardRef("SomeClass")]ForwardRef 不應由使用者例項化,但可由內省工具使用。

備註

PEP 585 泛型型別(例如 list["SomeClass"])不會隱式轉換為 list[ForwardRef("SomeClass")],因此不會自動解析為 list[SomeClass]

3.7.4 版本新增。

版本 3.14 中的變化: 這現在是 annotationlib.ForwardRef 的別名。此類的幾個未文件行為已更改;例如,在評估 ForwardRef 之後,評估值不再快取。

typing.evaluate_forward_ref(forward_ref, *, owner=None, globals=None, locals=None, type_params=None, format=annotationlib.Format.VALUE)

annotationlib.ForwardRef 評估為 型別提示

這類似於呼叫 annotationlib.ForwardRef.evaluate(),但與該方法不同,evaluate_forward_ref() 還會遞迴地評估型別提示中巢狀的前向引用。

有關 ownerglobalslocalstype_paramsformat 引數的含義,請參閱 annotationlib.ForwardRef.evaluate() 的文件。

注意

此函式可能會執行註解中包含的任意程式碼。有關更多資訊,請參閱 內省註解的安全影響

在 3.14 版本加入。

typing.NoDefault

一個哨兵物件,用於指示型別引數沒有預設值。例如

>>> T = TypeVar("T")
>>> T.__default__ is typing.NoDefault
True
>>> S = TypeVar("S", default=None)
>>> S.__default__ is None
True

在 3.13 版本加入。

常量

typing.TYPE_CHECKING

一個特殊常量,被第三方靜態型別檢查器假定為 True。它在執行時為 False

一個匯入開銷大,且僅包含用於型別註解的型別的模組,可以安全地匯入在 if TYPE_CHECKING: 塊中。這阻止了該模組在執行時實際匯入;註解不會急切地評估(參見 PEP 649),因此在註解中使用未定義的符號是無害的——只要您以後不檢查它們。您的靜態型別分析工具將在靜態型別分析期間將 TYPE_CHECKING 設定為 True,這意味著該模組將被匯入,並且在這樣的分析期間型別將被正確檢查。

用法

if TYPE_CHECKING:
    import expensive_mod

def fun(arg: expensive_mod.SomeType) -> None:
    local_var: expensive_mod.AnotherType = other_fun()

如果您偶爾需要在執行時檢查可能包含未定義符號的型別註解,請使用 annotationlib.get_annotations() 並將 format 引數設定為 annotationlib.Format.STRINGannotationlib.Format.FORWARDREF,以安全地檢索註解而不會引發 NameError

3.5.2 版本新增。

已棄用的別名

此模組定義了幾個已棄用的別名,指向預先存在的標準庫類。這些別名最初包含在 typing 模組中,以支援使用 [] 對這些泛型類進行引數化。然而,在 Python 3.9 中,當相應的預先存在的類被增強以支援 [] 時(參見 PEP 585),這些別名變得多餘。

這些冗餘型別自 Python 3.9 起已棄用。但是,雖然這些別名可能會在某個時候被刪除,但目前沒有計劃刪除它們。因此,直譯器目前不會為這些別名發出棄用警告。

如果在某個時候決定刪除這些已棄用的別名,直譯器將在刪除前至少兩個版本發出棄用警告。這些別名保證在 typing 模組中保留,且不發出棄用警告,直到至少 Python 3.14。

建議型別檢查器在程式目標最小 Python 版本為 3.9 或更高版本時,標記已棄用型別的使用。

內建型別的別名

class typing.Dict(dict, MutableMapping[KT, VT])

已棄用的 dict 別名。

請注意,為了註解引數,最好使用抽象集合型別(如 Mapping),而不是使用 dicttyping.Dict

自 3.9 版本棄用: builtins.dict 現在支援下標([])。請參閱 PEP 585泛型別名型別

class typing.List(list, MutableSequence[T])

已棄用的 list 別名。

請注意,為了註解引數,最好使用抽象集合型別(如 SequenceIterable),而不是使用 listtyping.List

自 3.9 版本棄用: builtins.list 現在支援下標([])。請參閱 PEP 585泛型別名型別

class typing.Set(set, MutableSet[T])

已棄用的 builtins.set 別名。

請注意,為了註解引數,最好使用抽象集合型別(如 collections.abc.Set),而不是使用 settyping.Set

自 3.9 版本棄用: builtins.set 現在支援下標([])。請參閱 PEP 585泛型別名型別

class typing.FrozenSet(frozenset, AbstractSet[T_co])

已棄用的 builtins.frozenset 別名。

自 3.9 版本棄用: builtins.frozenset 現在支援下標([])。請參閱 PEP 585泛型別名型別

typing.Tuple

已棄用的 tuple 別名。

tupleTuple 在型別系統中是特殊處理的;有關更多詳細資訊,請參閱 註解元組

自 3.9 版本棄用: builtins.tuple 現在支援下標([])。請參閱 PEP 585泛型別名型別

class typing.Type(Generic[CT_co])

已棄用的 type 別名。

有關在型別註解中使用 typetyping.Type 的詳細資訊,請參閱 類物件的型別

3.5.2 版本新增。

自 3.9 版本棄用: builtins.type 現在支援下標([])。請參閱 PEP 585泛型別名型別

collections 中型別的別名

class typing.DefaultDict(collections.defaultdict, MutableMapping[KT, VT])

已棄用的 collections.defaultdict 別名。

3.5.2 版本新增。

自 3.9 版本棄用: collections.defaultdict 現在支援下標([])。請參閱 PEP 585泛型別名型別

class typing.OrderedDict(collections.OrderedDict, MutableMapping[KT, VT])

已棄用的 collections.OrderedDict 別名。

3.7.2 版本新增。

自 3.9 版本棄用: collections.OrderedDict 現在支援下標([])。請參閱 PEP 585泛型別名型別

class typing.ChainMap(collections.ChainMap, MutableMapping[KT, VT])

已棄用的 collections.ChainMap 別名。

3.6.1 版本新增。

自 3.9 版本棄用: collections.ChainMap 現在支援下標([])。請參閱 PEP 585泛型別名型別

class typing.Counter(collections.Counter, Dict[T, int])

已棄用的 collections.Counter 別名。

3.6.1 版本新增。

自 3.9 版本棄用: collections.Counter 現在支援下標([])。請參閱 PEP 585泛型別名型別

class typing.Deque(deque, MutableSequence[T])

已棄用的 collections.deque 別名。

3.6.1 版本新增。

自 3.9 版本棄用: collections.deque 現在支援下標([])。請參閱 PEP 585泛型別名型別

其他具體型別的別名

class typing.Pattern
class typing.Match

已棄用的別名,對應於 re.compile()re.match() 的返回型別。

這些型別(和相應的函式)是泛型於 AnyStr 的。Pattern 可以特化為 Pattern[str]Pattern[bytes]Match 可以特化為 Match[str]Match[bytes]

自 3.9 版本棄用: re 模組中的 PatternMatch 類現在支援 []。參見 PEP 585泛型別名型別

class typing.Text

str 的棄用別名。

提供 Text 是為了給 Python 2 程式碼提供一個向前相容的路徑:在 Python 2 中,Textunicode 的別名。

使用 Text 來表示一個值必須包含一個與 Python 2 和 Python 3 都相容的 unicode 字串。

def add_unicode_checkmark(text: Text) -> Text:
    return text + u' \u2713'

3.5.2 版本新增。

自 3.11 版本棄用: Python 2 已不再受支援,並且大多數型別檢查器也不再支援對 Python 2 程式碼進行型別檢查。目前沒有計劃移除此別名,但鼓勵使用者使用 str 而不是 Text

collections.abc 中的容器抽象基類的別名

class typing.AbstractSet(Collection[T_co])

collections.abc.Set 的棄用別名。

自 3.9 版本棄用: collections.abc.Set 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.ByteString(Sequence[int])

collections.abc.ByteString 的棄用別名。

在執行時,使用 isinstance(obj, collections.abc.Buffer) 來測試 obj 是否實現了緩衝區協議。在型別註解中,可以使用 Buffer 或顯式指定程式碼支援的型別的聯合(例如,bytes | bytearray | memoryview)。

ByteString 最初旨在成為一個抽象類,它將作為 bytesbytearray 的超型別。然而,由於這個 ABC 從未有任何方法,因此知道一個物件是 ByteString 的例項實際上並未提供任何有用的資訊。其他常見的緩衝區型別,如 memoryview,也從未被視為 ByteString 的子型別(無論是執行時還是靜態型別檢查器)。

更多詳情請參見 PEP 688

自 3.9 版本棄用,將於 3.17 版本移除。

class typing.Collection(Sized, Iterable[T_co], Container[T_co])

collections.abc.Collection 的棄用別名。

在 3.6 版本加入。

自 3.9 版本棄用: collections.abc.Collection 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.Container(Generic[T_co])

collections.abc.Container 的棄用別名。

自 3.9 版本棄用: collections.abc.Container 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]])

collections.abc.ItemsView 的棄用別名。

自 3.9 版本棄用: collections.abc.ItemsView 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.KeysView(MappingView, AbstractSet[KT_co])

collections.abc.KeysView 的棄用別名。

自 3.9 版本棄用: collections.abc.KeysView 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.Mapping(Collection[KT], Generic[KT, VT_co])

collections.abc.Mapping 的棄用別名。

自 3.9 版本棄用: collections.abc.Mapping 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.MappingView(Sized)

collections.abc.MappingView 的棄用別名。

自 3.9 版本棄用: collections.abc.MappingView 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.MutableMapping(Mapping[KT, VT])

collections.abc.MutableMapping 的棄用別名。

自 3.9 版本棄用: collections.abc.MutableMapping 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.MutableSequence(Sequence[T])

collections.abc.MutableSequence 的棄用別名。

自 3.9 版本棄用: collections.abc.MutableSequence 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.MutableSet(AbstractSet[T])

collections.abc.MutableSet 的棄用別名。

自 3.9 版本棄用: collections.abc.MutableSet 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.Sequence(Reversible[T_co], Collection[T_co])

collections.abc.Sequence 的棄用別名。

自 3.9 版本棄用: collections.abc.Sequence 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.ValuesView(MappingView, Collection[_VT_co])

collections.abc.ValuesView 的棄用別名。

自 3.9 版本棄用: collections.abc.ValuesView 現在支援下標 ([])。參見 PEP 585泛型別名型別

collections.abc 中的非同步抽象基類的別名

class typing.Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType])

collections.abc.Coroutine 的棄用別名。

有關在型別註解中使用 collections.abc.Coroutinetyping.Coroutine 的詳細資訊,請參見 註解生成器和協程

3.5.3 版本新增。

自 3.9 版本棄用: collections.abc.Coroutine 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType])

collections.abc.AsyncGenerator 的棄用別名。

有關在型別註解中使用 collections.abc.AsyncGeneratortyping.AsyncGenerator 的詳細資訊,請參見 註解生成器和協程

3.6.1 版本新增。

自 3.9 版本棄用: collections.abc.AsyncGenerator 現在支援下標 ([])。參見 PEP 585泛型別名型別

3.13 版本中的變化: SendType 引數現在有預設值。

class typing.AsyncIterable(Generic[T_co])

collections.abc.AsyncIterable 的棄用別名。

3.5.2 版本新增。

自 3.9 版本棄用: collections.abc.AsyncIterable 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.AsyncIterator(AsyncIterable[T_co])

collections.abc.AsyncIterator 的棄用別名。

3.5.2 版本新增。

自 3.9 版本棄用: collections.abc.AsyncIterator 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.Awaitable(Generic[T_co])

collections.abc.Awaitable 的棄用別名。

3.5.2 版本新增。

自 3.9 版本棄用: collections.abc.Awaitable 現在支援下標 ([])。參見 PEP 585泛型別名型別

collections.abc 中其他抽象基類的別名

class typing.Iterable(Generic[T_co])

collections.abc.Iterable 的棄用別名。

自 3.9 版本棄用: collections.abc.Iterable 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.Iterator(Iterable[T_co])

collections.abc.Iterator 的棄用別名。

自 3.9 版本棄用: collections.abc.Iterator 現在支援下標 ([])。參見 PEP 585泛型別名型別

typing.Callable

collections.abc.Callable 的棄用別名。

有關如何在型別註解中使用 collections.abc.Callabletyping.Callable 的詳細資訊,請參見 註解可呼叫物件

自 3.9 版本棄用: collections.abc.Callable 現在支援下標 ([])。參見 PEP 585泛型別名型別

3.10 版本中的變化: Callable 現在支援 ParamSpecConcatenate。更多詳情請參見 PEP 612

class typing.Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType])

collections.abc.Generator 的棄用別名。

有關在型別註解中使用 collections.abc.Generatortyping.Generator 的詳細資訊,請參見 註解生成器和協程

自 3.9 版本棄用: collections.abc.Generator 現在支援下標 ([])。參見 PEP 585泛型別名型別

3.13 版本中的變化: 添加了傳送和返回型別的預設值。

class typing.Hashable

collections.abc.Hashable 的棄用別名。

自 3.12 版本棄用: 請直接使用 collections.abc.Hashable

class typing.Reversible(Iterable[T_co])

collections.abc.Reversible 的棄用別名。

自 3.9 版本棄用: collections.abc.Reversible 現在支援下標 ([])。參見 PEP 585泛型別名型別

class typing.Sized

collections.abc.Sized 的棄用別名。

自 3.12 版本棄用: 請直接使用 collections.abc.Sized

contextlib 抽象基類的別名

class typing.ContextManager(Generic[T_co, ExitT_co])

contextlib.AbstractContextManager 的棄用別名。

第一個型別引數 T_co 代表由 __enter__() 方法返回的型別。可選的第二個型別引數 ExitT_co (預設為 bool | None)代表由 __exit__() 方法返回的型別。

在 3.5.4 版本中新增。

自 3.9 版本棄用: contextlib.AbstractContextManager 現在支援下標 ([])。參見 PEP 585泛型別名型別

3.13 版本中的變化: 添加了可選的第二個型別引數 ExitT_co

class typing.AsyncContextManager(Generic[T_co, AExitT_co])

contextlib.AbstractAsyncContextManager 的棄用別名。

第一個型別引數 T_co 代表由 __aenter__() 方法返回的型別。可選的第二個型別引數 AExitT_co (預設為 bool | None)代表由 __aexit__() 方法返回的型別。

在 3.6.2 版本中新增。

自 3.9 版本棄用: contextlib.AbstractAsyncContextManager 現在支援下標 ([])。參見 PEP 585泛型別名型別

3.13 版本中的變化: 添加了可選的第二個型別引數 AExitT_co

主要功能棄用時間表

typing 中的某些功能已棄用,並可能在未來版本的 Python 中移除。下表總結了主要的棄用功能,以方便查閱。此表可能會有變動,並非所有棄用功能都已列出。

功能

棄用版本

預計移除版本

PEP/問題

typing 版本的標準集合

3.9

未定(詳見 棄用別名

PEP 585

typing.ByteString

3.9

3.17

gh-91896

typing.Text

3.11

未定

gh-92332

typing.Hashabletyping.Sized

3.12

未定

gh-94309

typing.TypeAlias

3.12

未定

PEP 695

@typing.no_type_check_decorator

3.13

3.15

gh-106309

typing.AnyStr

3.13

3.18

gh-105578