键入 — 支持类型提示 — Python 文档

来自菜鸟教程
Python/docs/3.10/library/typing
跳转至:导航、​搜索

typing — 支持类型提示

3.5 版中的新功能。


源代码: :source:`Lib/typing.py`

笔记

Python 运行时不强制执行函数和变量类型注释。 它们可以被第三方工具使用,例如类型检查器、IDE、linter 等。



该模块为类型提示提供运行时支持。 最基本的支持包括 AnyUnionCallableTypeVarGeneric 类型。 有关完整规范,请参阅 PEP 484。 有关类型提示的简化介绍,请参阅 PEP 483

下面的函数接受并返回一个字符串,注释如下:

def greeting(name: str) -> str:
    return 'Hello ' + name

在函数 greeting 中,参数 name 的类型应为 str,返回类型为 str。 子类型被接受为参数。

相关政治人物

自从 PEP 484PEP 483 中最初引入类型提示以来,许多 PEP 已经修改和增强了 Python 的类型框架注释。 这些包括:


类型别名

类型别名是通过将类型分配给别名来定义的。 在本例中,Vectorlist[float] 将被视为可互换的同义词:

Vector = list[float]

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

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

类型别名对于简化复杂的类型签名很有用。 例如:

from collections.abc import Sequence

ConnectionOptions = dict[str, str]
Address = tuple[str, int]
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:
    ...

请注意,作为类型提示的 None 是一种特殊情况,并由 type(None) 替换。


新类型

使用 NewType 辅助类创建不同的类型:

from typing import NewType

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

静态类型检查器会将新类型视为原始类型的子类。 这有助于捕获逻辑错误:

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

# typechecks
user_a = get_user_name(UserId(42351))

# does not typecheck; 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 typecheck
class AdminUserId(UserId): pass

但是,可以基于“派生”NewType 创建 NewType

from typing import NewType

UserId = NewType('UserId', int)

ProUserId = NewType('ProUserId', UserId)

ProUserId 的类型检查将按预期工作。

有关更多详细信息,请参阅 PEP 484

笔记

回想一下,类型别名的使用将两种类型声明为彼此 等价 。 执行 Alias = Original 将使静态类型检查器在所有情况下将 Alias 视为 Original 完全等效的 。 当您想要简化复杂的类型签名时,这很有用。

相反, NewType 将一种类型声明为另一种类型的 子类型 。 执行 Derived = NewType('Derived', Original) 将使静态类型检查器将 Derived 视为 Original子类 ,这意味着 Original 类型的值不能用于需要 Derived 类型值的地方。 当您希望以最小的运行成本防止逻辑错误时,这很有用。


版本 3.5.2 中的新功能。


在 3.10 版更改:NewType 现在是一个类而不是一个函数。 通过常规函数调用 NewType 时会产生一些额外的运行时成本。 但是,此成本将在 3.11.0 中降低。


可调用

需要特定签名的回调函数的框架可能会使用 Callable[[Arg1Type, Arg2Type], ReturnType] 进行类型提示。

例如:

from collections.abc import Callable

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

通过用文字省略号替换类型提示中的参数列表,可以在不指定调用签名的情况下声明可调用的返回类型:Callable[..., ReturnType]

将其他可调用对象作为参数的可调用对象可能会使用 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

def notify_by_email(employees: Sequence[Employee],
                    overrides: Mapping[str, str]) -> None: ...

泛型可以通过使用称为 TypeVar 的新工厂进行参数化。

from collections.abc import Sequence
from typing import TypeVar

T = TypeVar('T')      # Declare type variable

def first(l: Sequence[T]) -> T:   # Generic function
    return l[0]

用户定义的泛型类型

用户定义的类可以定义为泛型类。

from typing import TypeVar, Generic
from logging import Logger

T = TypeVar('T')

class LoggedVar(Generic[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)

Generic[T] 作为基类定义了类 LoggedVar 采用单个类型参数 T 。 这也使 T 作为类体内的类型有效。

Generic 基类定义了 __class_getitem__() 以便 LoggedVar[t] 作为类型有效:

from collections.abc import Iterable

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

泛型类型可以有任意数量的类型变量,并且类型变量可能受到约束:

from typing import TypeVar, Generic
...

T = TypeVar('T')
S = TypeVar('S', int, str)

class StrangePair(Generic[T, S]):
    ...

Generic 的每个类型变量参数必须是不同的。 因此这是无效的:

from typing import TypeVar, Generic
...

T = TypeVar('T')

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

您可以将多重继承与 Generic 一起使用:

from collections.abc import Sized
from typing import TypeVar, Generic

T = TypeVar('T')

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

从泛型类继承时,可以修复一些类型变量:

from collections.abc import Mapping
from typing import TypeVar

T = TypeVar('T')

class MyDict(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
from typing import TypeVar
S = TypeVar('S')
Response = Iterable[S] | int

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

T = TypeVar('T', int, float, complex)
Vec = Iterable[tuple[T, T]]

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

3.7 版更改:Generic 不再有自定义元类。


通过 Generic[P] 形式的参数规范变量也支持用户定义的参数表达式泛型。 该行为与上述类型变量一致,因为类型模块将参数规范变量视为专用类型变量。 对此的一个例外是类型列表可用于替换 ParamSpec

>>> from typing import Generic, ParamSpec, TypeVar

>>> T = TypeVar('T')
>>> P = ParamSpec('P')

>>> class Z(Generic[T, P]): ...
...
>>> Z[int, [dict, float]]
__main__.Z[int, (<class 'dict'>, <class 'float'>)]

此外,出于美观原因,只有一个参数规范变量的泛型将接受 XPython/docs/3.10/library/Type1, Type2, ..X[Type1, Type2, ...] 形式的参数列表。 在内部,后者被转换为前者,因此是等价的:

>>> class X(Generic[P]): ...
...
>>> X[int, str]
__main__.X[(<class 'int'>, <class 'str'>)]
>>> X[[../int, str]]
__main__.X[(<class 'int'>, <class 'str'>)]

请注意,在某些情况下,具有 ParamSpec 的泛型在替换后可能没有正确的 __parameters__,因为它们主要用于静态类型检查。

在 3.10 版更改:Generic 现在可以通过参数表达式进行参数化。 有关更多详细信息,请参阅 ParamSpecPEP 612


用户定义的泛型类可以将 ABC 作为基类,而不会发生元类冲突。 不支持通用元类。 参数化泛型的结果会被缓存,并且typing 模块中的大多数类型都是可散列的并且可以比较相等。


Any 类型

一种特殊的类型是 Any。 静态类型检查器会将每种类型视为与 Any 兼容,将 Any 视为与每种类型兼容。

这意味着可以对 Any 类型的值执行任何操作或方法调用并将其分配给任何变量:

from typing import Any

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

s = ''      # type: str
s = a       # OK

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

请注意,将 Any 类型的值分配给更精确的类型时,不会执行类型检查。 例如,静态类型检查器在将 a 分配给 s 时没有报告错误,即使 s 被声明为类型 str 并接收运行时的 int 值!

此外,所有没有返回类型或参数类型的函数将隐式默认使用 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 不同的是,反过来就不成立了:objectnot 所有其他类型的子类型。

这意味着当值的类型是 object 时,类型检查器将拒绝对其进行几乎所有操作,并将其分配给更特殊类型的变量(或将其用作返回值)是一个类型错误。 例如:

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

def hash_b(item: Any) -> int:
    # Typechecks
    item.magic()
    ...

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

# Typechecks, since Any is compatible with all types
hash_b(42)
hash_b("foo")

使用 object 指示值可以是类型安全的任何类型。 使用 Any 表示一个值是动态类型的。


名义与结构子类型

最初 PEP 484 将 Python 静态类型系统定义为使用 名义子类型 。 这意味着当且仅当 AB 的子类时,允许类 A,其中需要类 B

此要求以前也适用于抽象基类,例如 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 进行子类化,用户可以定义新的自定义协议以充分享受结构子类型化(请参见下面的示例)。


模块内容

该模块定义了以下类、函数和装饰器。

笔记

该模块定义了几种类型,它们是预先存在的标准库类的子类,这些类还扩展了 Generic 以支持 [] 中的类型变量。 当相应的预先存在的类被增强以支持 [] 时,这些类型在 Python 3.9 中变得多余。

从 Python 3.9 开始,冗余类型已被弃用,但解释器不会发出弃用警告。 当被检查的程序面向 Python 3.9 或更新版本时,类型检查器将标记已弃用的类型。

在 Python 3.9.0 发布 5 年后发布的第一个 Python 版本中,已弃用的类型将从 typing 模块中删除。 请参阅 PEP 585标准集合中的类型提示泛型 中的详细信息。


特殊类型原语

特殊类型

这些可以用作注释中的类型,并且不支持 []

typing.Any
表示无约束类型的特殊类型。
  • 每种类型都与 Any 兼容。
  • Any 兼容所有类型。
typing.NoReturn

指示函数永不返回的特殊类型。 例如:

from typing import NoReturn

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

3.5.4 版中的新功能。

版本 3.6.2 中的新功能。

typing.TypeAlias

用于显式声明 类型别名 的特殊注释。 例如:

from typing import TypeAlias

Factors: TypeAlias = list[int]

有关显式类型别名的更多详细信息,请参阅 PEP 613

3.10 版中的新功能。


特殊表格

这些可以用作使用 [] 的注释中的类型,每个都有独特的语法。

typing.Tuple

元组类型; Tuple[X, Y] 是两个元素的元组类型,第一个元素是 X 类型,第二个元素是 Y 类型。 空元组的类型可以写成Tuple[()]

示例: Tuple[T1, T2] 是对应于类型变量 T1 和 T2 的两个元素的元组。 Tuple[int, float, str] 是一个 int、一个浮点数和一个字符串的元组。

要指定同构类型的可变长度元组,请使用文字省略号,例如 Tuple[int, ...]。 一个普通的 Tuple 等价于 Tuple[Any, ...],反过来又相当于 tuple

自 3.9 版起已弃用:builtins.tuple 现在支持 []。 请参阅 PEP 585通用别名类型

typing.Union

联合类型; Union[X, Y] 相当于 X | Y,表示 X 或 Y。

要定义联合,请使用例如 Union[int, str] 或简写 int | str。 细节:

  • 参数必须是类型,并且必须至少有一个。

  • 工会的工会被扁平化,例如:

    Union[Union[int, str], 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。 请参阅 联合类型表达式

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.Callable

可调用类型; Callable[[int], str] 是 (int) -> str 的函数。

订阅语法必须始终与两个值一起使用:参数列表和返回类型。 参数列表必须是类型列表或省略号; 返回类型必须是单一类型。

没有指示可选参数或关键字参数的语法; 此类函数类型很少用作回调类型。 Callable[..., ReturnType](字面省略号)可用于键入hint a callable 接受任意数量的参数并返回ReturnType。 一个普通的 Callable 等价于 Callable[..., Any],进而相当于 collections.abc.Callable

将其他可调用对象作为参数的可调用对象可能会使用 ParamSpec 指示它们的参数类型相互依赖。 此外,如果该可调用对象从其他可调用对象中添加或删除参数,则可以使用 Concatenate 运算符。 它们分别采用 Callable[ParamSpecVariable, ReturnType]Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType] 的形式。

自 3.9 版起已弃用:collections.abc.Callable 现在支持 []。 请参阅 PEP 585通用别名类型

在 3.10 版更改:Callable 现在支持 ParamSpecConcatenate。 有关更多信息,请参阅 PEP 612

也可以看看

ParamSpecConcatenate 的文档提供了 Callable 的使用示例。

typing.Concatenate

CallableParamSpec 一起使用来注释高阶可调用对象,它添加、删除或转换另一个可调用对象的参数。 使用形式为 Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]Concatenate 当前仅在用作 Callable 的第一个参数时才有效。 Concatenate 的最后一个参数必须是 ParamSpec

例如,要注释为装饰函数提供 threading.Lock 的装饰器 with_lock,可以使用 Concatenate 指示 with_lock 期望一个callable 接受一个 Lock 作为第一个参数,并返回一个具有不同类型签名的 callable。 在这种情况下, ParamSpec 表示返回的可调用的参数类型取决于传入的可调用的参数类型:

from collections.abc import Callable
from threading import Lock
from typing import Any, Concatenate, ParamSpec, TypeVar

P = ParamSpec('P')
R = TypeVar('R')

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

def with_lock(f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]:
    '''A type-safe decorator which provides a lock.'''
    global my_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 版中的新功能。


也可以看看


class typing.Type(Generic[CT_co])

C 注释的变量可以接受类型为 C 的值。 相比之下,用 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 BasicUser(User): ...
class ProUser(User): ...
class TeamUser(User): ...

# Accepts User, BasicUser, ProUser, TeamUser, ...
def make_new_user(user_class: Type[User]) -> User:
    # ...
    return user_class()

Type[C] 是协变的这一事实意味着 C 的所有子类应该实现与 C 相同的构造函数签名和类方法签名。 类型检查器应该标记违反这一点,但也应该允许子类中的构造函数调用与指定基类中的构造函数调用相匹配。 在 PEP 484 的未来修订版中,类型检查器如何处理这种特殊情况可能会发生变化。

Type 的唯一合法参数是类、Any类型变量 和任何这些类型的联合。 例如:

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

Type[Any] 相当于 Type,后者又相当于 type,这是 Python 元类层次结构的根。

版本 3.5.2 中的新功能。

自 3.9 版起已弃用:builtins.type 现在支持 []。 请参阅 PEP 585通用别名类型

typing.Literal

一种类型,可用于向类型检查器指示相应的变量或函数参数具有与提供的文字(或多个文字之一)等效的值。 例如:

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

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

3.8 版中的新功能。

在 3.9.1 版更改:Literal 现在去除重复参数。 Literal 对象的相等比较不再依赖于顺序。 Literal 对象现在将在相等比较期间引发 TypeError 异常,如果它们的参数之一不是 hashable

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 版中的新功能。

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 版中的新功能。

typing.Annotated

PEP 593 (Flexible function and variable annotations) 中引入的一种类型,用于使用特定于上下文的元数据(可能是它的多个部分,如 Annotated)来装饰现有类型] 是可变参数)。 具体来说,类型 T 可以通过类型提示 Annotated[T, x] 用元数据 x 进行注释。 此元数据可用于静态分析或运行时。 如果库(或工具)遇到类型提示 Annotated[T, x] 并且没有特殊的元数据逻辑 x,它应该忽略它并简单地将类型视为 T。 与 typing 模块中当前存在的 no_type_check 功能完全禁用对函数或类的类型检查注释不同,Annotated 类型允许对 T(例如,通过 mypy 或 Pyre,可以安全地忽略 x)以及在特定应用程序中对 x 的运行时访问。

最终,如何解释注释(如果有的话)是遇到 Annotated 类型的工具或库的责任。 遇到 Annotated 类型的工具或库可以扫描注释以确定它们是否感兴趣(例如,使用 isinstance())。

当工具或库不支持注解或遇到未知注解时,它应该忽略它并将注解类型视为基础类型。

由使用注释的工具决定是否允许客户端在一种类型上有多个注释以及如何合并这些注释。

由于 Annotated 类型允许您在任何节点上放置多个相同(或不同)类型的注释,使用这些注释的工具或库负责处理潜在的重复项。 例如,如果您正在进行值范围分析,您可能会允许:

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

include_extras=True 传递给 get_type_hints() 可以在运行时访问额外的注释。

语法细节:

  • Annotated 的第一个参数必须是有效类型

  • 支持多种类型注释(Annotated 支持可变参数):

    Annotated[int, ValueRange(3, 10), ctype("char")]
  • Annotated 必须至少用两个参数调用( Annotated[int] 无效)

  • 注释的顺序被保留并且对于相等性检查很重要:

    Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[
        int, ctype("char"), ValueRange(3, 10)
    ]
  • 嵌套的 Annotated 类型被展平,元数据从最里面的注释开始排序:

    Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
        int, ValueRange(3, 10), ctype("char")
    ]
  • 不会删除重复的注释:

    Annotated[int, ValueRange(3, 10)] != Annotated[
        int, ValueRange(3, 10), ValueRange(3, 10)
    ]
  • Annotated 可以与嵌套和通用别名一起使用:

    T = TypeVar('T')
    Vec = Annotated[list[tuple[T, T]], MaxLen(10)]
    V = Vec[int]
    
    V == Annotated[list[tuple[int, int]], MaxLen(10)]

3.9 版中的新功能。

typing.TypeGuard

用于注释用户定义类型保护函数的返回类型的特殊类型形式。 TypeGuard 只接受一个类型参数。 在运行时,以这种方式标记的函数应该返回一个布尔值。

TypeGuard 旨在使 类型缩小 受益——静态类型检查器使用一种技术来确定程序代码流中更精确的表达式类型。 通常类型缩小是通过分析条件代码流并将缩小应用于代码块来完成的。 这里的条件表达式有时被称为“类型保护”:

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

有时使用用户定义的布尔函数作为类型保护会很方便。 这样的函数应该使用 TypeGuard[...] 作为它的返回类型来警告静态类型检查器这个意图。

使用 -> TypeGuard 告诉静态类型检查器对于给定的函数:

  1. 返回值是一个布尔值。

  2. 如果返回值为True,则其参数类型为TypeGuard里面的类型。

    例如:

    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!")

如果 is_str_list 是类或实例方法,则 TypeGuard 中的类型映射到 clsself 之后的第二个参数的类型。

简而言之,形式def foo(arg: TypeA) -> TypeGuard[TypeB]: ...,表示如果foo(arg)返回True,那么argTypeA缩小到TypeB ]。

笔记

TypeB 不必是 TypeA 的较窄形式——它甚至可以是较宽的形式。 主要原因是允许将 List[object] 缩小到 List[str],即使后者不是前者的子类型,因为 List 是不变的。 编写类型安全的类型保护的责任留给了用户。

TypeGuard 也适用于类型变量。 有关更多信息,请参阅 PEP 647(用户定义的类型保护)。

3.10 版中的新功能。


构建泛型类型

这些不在注释中使用。 它们是用于创建泛型类型的构建块。

class typing.Generic

泛型类型的抽象基类。

泛型类型通常通过从具有一个或多个类型变量的此类的实例化继承来声明。 例如,通用映射类型可能定义为:

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

然后可以按如下方式使用此类:

X = TypeVar('X')
Y = TypeVar('Y')

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

类型变量。

用法:

T = TypeVar('T')  # Can be anything
A = TypeVar('A', str, bytes)  # Must be str or bytes

类型变量的存在主要是为了静态类型检查器的好处。 它们用作泛型类型以及泛型函数定义的参数。 有关泛型类型的更多信息,请参阅 Generic。 通用函数的工作方式如下:

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

def longest(x: A, y: A) -> A:
    """Return the longest of two strings."""
    return x if len(x) >= len(y) else y

后一个例子的签名本质上是(str, str) -> str(bytes, bytes) -> bytes的重载。 还要注意,如果参数是 str 的某个子类的实例,返回类型仍然是普通的 str

在运行时,isinstance(x, T) 将引发 TypeError。 通常, isinstance()issubclass() 不应与类型一起使用。

类型变量可以通过传递 covariant=Truecontravariant=True 来标记协变或逆变。 有关更多详细信息,请参阅 PEP 484。 默认情况下,类型变量是不变的。 或者,类型变量可以使用 bound=<type> 指定上限。 这意味着替换(显式或隐式)类型变量的实际类型必须是边界类型的子类,请参阅 PEP 484

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

参数规范变量。 类型变量 的专用版本。

用法:

P = ParamSpec('P')

参数规范变量的存在主要是为了静态类型检查器的好处。 它们用于将一个可调用对象的参数类型转发到另一个可调用对象——一种常见于高阶函数和装饰器的模式。 它们仅在用于 Concatenate,或作为 Callable 的第一个参数,或作为用户定义泛型的参数时才有效。 有关泛型类型的更多信息,请参阅 Generic

例如,要向函数添加基本日志记录,可以创建一个装饰器 add_logging 来记录函数调用。 参数规范变量告诉类型检查器传递给装饰器的可调用对象和它返回的新可调用对象具有相互依赖的类型参数:

from collections.abc import Callable
from typing import TypeVar, ParamSpec
import logging

T = TypeVar('T')
P = ParamSpec('P')

def add_logging(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,以前注释的最简单方法是使用 TypeVar 绑定 Callable[..., Any]。 然而,这会导致两个问题:

  1. 类型检查器无法对 inner 功能进行类型检查,因为 *args**kwargs 必须键入 Any

  2. 返回 inner 函数时,add_logging 装饰器的主体中可能需要 cast(),或者必须告诉静态类型检查器忽略 [ X168X]。


args
kwargs

由于 ParamSpec 捕获位置参数和关键字参数,因此 P.argsP.kwargs 可用于将 ParamSpec 拆分为其组件。 P.args 表示给定调用中位置参数的元组,应该只用于注释 *argsP.kwargs 表示给定调用中关键字参数到它们的值的映射,并且应该仅用于注释 **kwargs。 这两个属性都要求带注释的参数在范围内。 在运行时,P.argsP.kwargs 分别是 ParamSpecArgsParamSpecKwargs 的实例。

使用 covariant=Truecontravariant=True 创建的参数规范变量可用于声明协变或逆变泛型类型。 bound 参数也被接受,类似于 TypeVar。 然而,这些关键字的实际语义尚未确定。

3.10 版中的新功能。

笔记

只有在全局范围内定义的参数规范变量才能被pickle。

也可以看看


typing.ParamSpecArgs
typing.ParamSpecKwargs

ParamSpec 的参数和关键字参数属性。 ParamSpecP.args属性是ParamSpecArgs的实例,P.kwargsParamSpecKwargs的实例。 它们用于运行时内省,对静态类型检查器没有特殊意义。

在这些对象中的任何一个上调用 get_origin() 将返回原始的 ParamSpec

P = ParamSpec("P")
get_origin(P.args)  # returns P
get_origin(P.kwargs)  # returns P

3.10 版中的新功能。

typing.AnyStr

AnyStr 是定义为 AnyStr = TypeVar('AnyStr', str, bytes) 的类型变量。

它旨在用于可以接受任何类型的字符串而不允许混合不同类型的字符串的函数。 例如:

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

concat(u"foo", u"bar")  # Ok, output has type 'unicode'
concat(b"foo", b"bar")  # Ok, output has type 'bytes'
concat(u"foo", b"bar")  # Error, cannot mix unicode and bytes
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()(稍后描述)修饰的协议类充当头脑简单的运行时协议,只检查给定属性的存在,而忽略它们的类型签名。

协议类可以是通用的,例如:

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

3.8 版中的新功能。

@typing.runtime_checkable

将协议类标记为运行时协议。

这样的协议可以与 isinstance()issubclass() 一起使用。 当应用于非协议类时,这会引发 TypeError。 这允许进行简单的结构检查,非常类似于 collections.abc 中的“一招小马”,例如 Iterable。 例如:

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

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

笔记

runtime_checkable() 将只检查所需方法的存在,而不是它们的类型签名。 例如,ssl.SSLObject 是一个类,因此它通过 issubclass()Callable 的检查。 然而,ssl.SSLObject.__init__() 方法的存在只是为了引发一个 TypeError 带有更多信息的消息,因此无法调用(实例化)ssl.SSLObject

3.8 版中的新功能。


其他特殊指令

这些不在注释中使用。 它们是用于声明类型的构建块。

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}>'

向后兼容用法:

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__ 属性。

class typing.NewType(name, tp)

用于向类型检查器指示不同类型的辅助类,请参阅 NewType。 在运行时,它返回一个对象,该对象在调用时返回其参数。 用法:

UserId = NewType('UserId', int)
first_user = UserId(1)

版本 3.5.2 中的新功能。

在 3.10 版更改:NewType 现在是一个类而不是一个函数。

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')

自省的类型信息可以通过 Point2D.__annotations__Point2D.__total__Point2D.__required_keys__Point2D.__optional_keys__ 访问。 为了允许将此功能与不支持 PEP 526 的旧版 Python 一起使用,TypedDict 支持两种额外的等效语法形式:

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

默认情况下,所有键都必须存在于 TypedDict 中。 可以通过指定总体来覆盖它。 用法:

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

这意味着 Point2D TypedDict 可以省略任何键。 类型检查器仅支持文字 FalseTrue 作为 total 参数的值。 True 是默认值,并且使类主体中定义的所有项都成为必需。

PEP 589的更多例子和使用TypedDict的详细规则参见

3.8 版中的新功能。


通用混凝土集合

对应内置类型

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

dict 的通用版本。 用于注释返回类型。 要注释参数,最好使用抽象集合类型,例如 Mapping

这种类型可以如下使用:

def count_words(text: str) -> Dict[str, int]:
    ...

自 3.9 版起已弃用:builtins.dict 现在支持 []。 请参阅 PEP 585通用别名类型

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

list 的通用版本。 用于注释返回类型。 要注释参数,最好使用抽象集合类型,例如 SequenceIterable

这种类型可以如下使用:

T = TypeVar('T', int, float)

def vec2(x: T, y: T) -> List[T]:
    return [x, y]

def keep_positives(vector: Sequence[T]) -> List[T]:
    return [item for item in vector if item > 0]

自 3.9 版起已弃用:builtins.list 现在支持 []。 请参阅 PEP 585通用别名类型

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

builtins.set 的通用版本。 用于注释返回类型。 要注释参数,最好使用抽象集合类型,例如 AbstractSet

自 3.9 版起已弃用:builtins.set 现在支持 []。 请参阅 PEP 585通用别名类型

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

builtins.frozenset 的通用版本。

自 3.9 版起已弃用:builtins.frozenset 现在支持 []。 请参阅 PEP 585通用别名类型

笔记

Tuple 是一种特殊形式。


对应于 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.5.4 版中的新功能。

版本 3.6.1 中的新功能。

自 3.9 版起已弃用:collections.ChainMap 现在支持 []。 请参阅 PEP 585通用别名类型

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

collections.Counter 的通用版本。

3.5.4 版中的新功能。

版本 3.6.1 中的新功能。

自 3.9 版起已弃用:collections.Counter 现在支持 []。 请参阅 PEP 585通用别名类型

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

collections.deque 的通用版本。

3.5.4 版中的新功能。

版本 3.6.1 中的新功能。

自 3.9 版起已弃用:collections.deque 现在支持 []。 请参阅 PEP 585通用别名类型


其他混凝土类型

class typing.IO

class typing.TextIO
class typing.BinaryIO

泛型类型 IO[AnyStr] 及其子类 TextIO(IO[str])BinaryIO(IO[bytes]) 表示 I/O 流的类型,例如由 open() 返回。
class typing.Pattern
class typing.Match

这些类型别名对应于 re.compile()re.match() 的返回类型。 这些类型(和相应的函数)在 AnyStr 中是通用的,可以通过写 Pattern[str]Pattern[bytes]Match[str] 或 [ X147X]。

自 3.9 版起已弃用:rePatternMatch 现在支持 []。 请参阅 PEP 585通用别名类型

class typing.Text

Textstr 的别名。 提供它是为了为 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 中的新功能。


抽象基类

对应于collections.abc中的集合

class typing.AbstractSet(Sized, Collection[T_co])

collections.abc.Set 的通用版本。

自 3.9 版起已弃用:collections.abc.Set 现在支持 []。 请参阅 PEP 585通用别名类型

class typing.ByteString(Sequence[int])

collections.abc.ByteString 的通用版本。

该类型表示字节序列的类型bytesbytearraymemoryview

作为这种类型的简写,bytes 可用于注释上述任何类型的参数。

自 3.9 版起已弃用:collections.abc.ByteString 现在支持 []。 请参阅 PEP 585通用别名类型

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

collections.abc.Collection 的通用版本

3.6.0 版中的新功能。

自 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, Generic[KT_co, VT_co])

collections.abc.ItemsView 的通用版本。

自 3.9 版起已弃用:collections.abc.ItemsView 现在支持 []。 请参阅 PEP 585通用别名类型

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

collections.abc.KeysView 的通用版本。

自 3.9 版起已弃用:collections.abc.KeysView 现在支持 []。 请参阅 PEP 585通用别名类型

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

collections.abc.Mapping 的通用版本。 这种类型可以如下使用:

def get_position_in_index(word_list: Mapping[str, int], word: str) -> int:
    return word_list[word]

自 3.9 版起已弃用:collections.abc.Mapping 现在支持 []。 请参阅 PEP 585通用别名类型

class typing.MappingView(Sized, Iterable[T_co])

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[VT_co])

collections.abc.ValuesView 的通用版本。

自 3.9 版起已弃用:collections.abc.ValuesView 现在支持 []。 请参阅 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通用别名类型

class typing.Generator(Iterator[T_co], Generic[T_co, T_contra, V_co])

生成器可以通过泛型类型 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, 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

自 3.9 版起已弃用:collections.abc.Generator 现在支持 []。 请参阅 PEP 585通用别名类型

class typing.Hashable
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 的别名


异步编程

class typing.Coroutine(Awaitable[V_co], Generic[T_co, T_contra, V_co])

collections.abc.Coroutine 的通用版本。 类型变量的方差和顺序对应于Generator,例如:

from collections.abc import Coroutine
c = None # type: Coroutine[list[str], str, int]
...
x = c.send('hi') # type: list[str]
async def bar() -> None:
    x = await c # type: int

3.5.3 版中的新功能。

自 3.9 版起已弃用:collections.abc.Coroutine 现在支持 []。 请参阅 PEP 585通用别名类型

class typing.AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra])

异步生成器可以通过通用类型 AsyncGenerator[YieldType, SendType] 进行注释。 例如:

async def echo_round() -> AsyncGenerator[int, float]:
    sent = yield 0
    while sent >= 0.0:
        rounded = await round(sent)
        sent = yield rounded

与普通生成器不同,异步生成器不能返回值,因此没有 ReturnType 类型参数。 与 Generator 一样,SendType 的行为也是逆变的。

如果您的生成器只会产生值,请将 SendType 设置为 None

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)

版本 3.6.1 中的新功能。

自 3.9 版起已弃用:collections.abc.AsyncGenerator 现在支持 []。 请参阅 PEP 585通用别名类型

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通用别名类型


上下文管理器类型

class typing.ContextManager(Generic[T_co])

contextlib.AbstractContextManager 的通用版本。

3.5.4 版中的新功能。

3.6.0 版中的新功能。

自 3.9 版起已弃用:contextlib.AbstractContextManager 现在支持 []。 请参阅 PEP 585通用别名类型

class typing.AsyncContextManager(Generic[T_co])

contextlib.AbstractAsyncContextManager 的通用版本。

3.5.4 版中的新功能。

版本 3.6.2 中的新功能。

自 3.9 版起已弃用:contextlib.AbstractAsyncContextManager 现在支持 []。 请参阅 PEP 585通用别名类型


协议

这些协议用 runtime_checkable() 修饰。

class typing.SupportsAbs
带有一个抽象方法 __abs__ 的 ABC,它的返回类型是协变的。
class typing.SupportsBytes
带有一个抽象方法 __bytes__ 的 ABC。
class typing.SupportsComplex
带有一个抽象方法 __complex__ 的 ABC。
class typing.SupportsFloat
带有一个抽象方法 __float__ 的 ABC。
class typing.SupportsIndex

带有一个抽象方法 __index__ 的 ABC。

3.8 版中的新功能。

class typing.SupportsInt
带有一个抽象方法 __int__ 的 ABC。
class typing.SupportsRound
带有一个抽象方法 __round__ 的 ABC,它的返回类型是协变的。


函数和装饰器

typing.cast(typ, val)

将值转换为类型。

这将返回不变的值。 对于类型检查器,这表明返回值具有指定的类型,但在运行时我们故意不检查任何东西(我们希望这尽可能快)。

@typing.overload

@overload 装饰器允许描述支持多种不同参数类型组合的函数和方法。 一系列 @overload 修饰的定义必须紧跟一个非 @overload 修饰的定义(对于相同的函数/方法)。 @overload 修饰的定义仅对类型检查器有益,因为它们将被非 @overload 修饰的定义覆盖,而后者在运行时使用但应忽略通过类型检查器。 在运行时,直接调用 @overload 修饰的函数将引发 NotImplementedError。 提供比使用联合或类型变量表示的类型更精确的重载示例:

@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>

有关详细信息以及与其他类型语义的比较,请参阅 PEP 484

@typing.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 版中的新功能。

@typing.no_type_check

装饰器来指示注释不是类型提示。

这用作类或函数 装饰器 。 对于一个类,它递归地应用于该类中定义的所有方法(但不适用于其超类或子类中定义的方法)。

这会改变适当的功能。

@typing.no_type_check_decorator

装饰器给另一个装饰器 no_type_check() 效果。

这用将装饰函数包装在 no_type_check() 中的东西包装了装饰器。

@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__ 相同。 此外,编码为字符串文字的前向引用是通过在 globalslocals 命名空间中评估它们来处理的。 如有必要,如果设置了等于 None 的默认值,则为函数和方法注释添加 Optional[t]。 对于类 C,返回一个字典,该字典是通过将所有 __annotations__ 沿 C.__mro__ 以相反顺序合并而成的。

该函数递归地将所有 Annotated[T, ...] 替换为 T,除非 include_extras 设置为 True(有关更多信息,请参阅 Annotated)。 例如:

class Student(NamedTuple):
    name: Annotated[str, 'some marker']

get_type_hints(Student) == {'name': str}
get_type_hints(Student, include_extras=False) == {'name': str}
get_type_hints(Student, include_extras=True) == {
    'name': Annotated[str, 'some marker']
}

笔记

get_type_hints() 不适用于包含前向引用的导入的 类型别名 。 启用注释的延迟评估 (PEP 563) 可以消除对大多数前向引用的需要。

在 3.9 版更改:添加 include_extras 参数作为 PEP 593 的一部分。

typing.get_args(tp)
typing.get_origin(tp)

为泛型类型和特殊类型形式提供基本的内省。

对于 X[Y, Z, ...] 形式的输入对象,这些函数返回 X(Y, Z, ...)。 如果 X 是内置类或 collections 类的通用别名,它会被标准化为原始类。 如果 X 是联合或 Literal 包含在另一个泛型类型中,则 (Y, Z, ...) 的顺序可能与原始参数 [Y, Z, ...] 的顺序不同,原因是类型缓存。 对于不受支持的对象,相应地返回 None()。 例子:

assert get_origin(Dict[str, int]) is dict
assert get_args(Dict[int, str]) == (int, str)

assert get_origin(Union[int, str]) is Union
assert get_args(Union[int, str]) == (int, str)

3.8 版中的新功能。

typing.is_typeddict(tp)

检查类型是否为 TypedDict

例如:

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

is_typeddict(Film)  # => True
is_typeddict(list | str)  # => False

3.10 版中的新功能。

class typing.ForwardRef

用于字符串前向引用的内部类型表示的类。 例如,List["SomeClass"] 隐式转换为 List[ForwardRef("SomeClass")]。 此类不应由用户实例化,但可由内省工具使用。

笔记

PEP 585 泛型类型如 list["SomeClass"] 不会隐式转换为 list[ForwardRef("SomeClass")],因此不会自动解析为 list[SomeClass]

版本 3.7.4 中的新功能。


持续的

typing.TYPE_CHECKING

第 3 方静态类型检查器假定为 True 的特殊常量。 运行时为 False。 用法:

if TYPE_CHECKING:
    import expensive_mod

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

第一个类型注释必须用引号括起来,使其成为“前向引用”,以从解释器运行时隐藏 expensive_mod 引用。 不评估局部变量的类型注释,因此不需要用引号将第二个注释括起来。

笔记

如果在 Python 3.7 或更高版本中使用 from __future__ import annotations,则不会在函数定义时评估注释。 相反,它们以字符串形式存储在 __annotations__ 中,这使得不必在注释周围使用引号。 (见 PEP 563)。

版本 3.5.2 中的新功能。