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