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

来自菜鸟教程
Python/docs/3.9/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 中的新功能。


可调用

需要特定签名的回调函数的框架可能会使用 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]


泛型

由于容器中保存的对象的类型信息不能以通用方式静态推断,抽象基类已被扩展以支持订阅以表示容器元素的预期类型。

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, Union
S = TypeVar('S')
Response = Union[Iterable[S], int]

# Return type here is same as Union[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 不再有自定义元类。


用户定义的泛型类可以将 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.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。

要定义联合,请使用例如 Union[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]
  • 比较联合时,将忽略参数顺序,例如:

    Union[int, str] == Union[str, int]
  • 您不能子类化或实例化联合。

  • 你不能写Union[X][Y]

  • 您可以使用 Optional[X] 作为 Union[X, None] 的简写。

3.7 版更改: 不要在运行时从联合中删除显式子类。

typing.Optional

可选类型。

Optional[X] 相当于 Union[X, None]

请注意,这与可选参数不同,后者具有默认值。 带有默认值的可选参数不需要 Optional 在其类型注释上的限定符,因为它是可选的。 例如:

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

另一方面,如果允许 None 的显式值,则使用 Optional 是合适的,无论参数是否可选。 例如:

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

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

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

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

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

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


构建泛型类型

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

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

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() 将只检查所需方法的存在,而不是它们的类型签名! 例如,builtins.complex 实现了 __float__(),因此它通过了 issubclass()SupportsFloat 的检查。 然而,complex.__float__ 方法的存在只是为了引发 TypeError 和更多信息性消息。

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

typing.NewType(name, tp)

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

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

版本 3.5.2 中的新功能。

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__ 访问自省的类型信息。 为了允许将此功能与不支持 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 可以省略任何键。 类型检查器只需要支持文字 False 或 True 作为 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']
}

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

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

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

对于 X[Y, Z, ...] 形式的输入对象,这些函数返回 X(Y, Z, ...)。 如果 X 是内置类或 collections 类的通用别名,它会被标准化为原始类。 如果 X 是包含在另一个泛型类型中的 UnionLiteral,则 (Y, Z, ...) 的顺序可能与原始参数的顺序不同 [ X169X] 由于类型缓存。 对于不受支持的对象,相应地返回 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 版中的新功能。

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