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
提示所示。
虽然类型提示可以是简单的类,如 float
或 str
,但它们也可以更复杂。typing
模块提供了一个更高级类型提示的词汇表。
typing
模块中经常添加新功能。typing_extensions 包为旧版本的 Python 提供了这些新功能的反向移植。
另请参阅
- “类型提示速查表”
类型提示的快速概述(托管在 mypy 文档中)
- mypy 文档 的“类型系统参考”部分
Python 类型系统是通过 PEP 标准化的,因此本参考应广泛适用于大多数 Python 类型检查器。(某些部分可能仍然是 mypy 特有的。)
- “使用 Python 进行静态类型检查”
由社区编写的与类型检查器无关的文档,详细介绍了类型系统功能、有用的类型相关工具和类型最佳实践。
Python 类型系统的规范¶
Python 类型系统的规范、最新规范可以在 “Python 类型系统规范” 中找到。
类型别名¶
类型别名是使用 type
语句定义的,该语句创建了一个 TypeAliasType
的实例。在本例中,静态类型检查器将等效地对待 Vector
和 list[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
订阅语法必须始终与两个值一起使用:参数列表和返回类型。参数列表必须是类型列表、ParamSpec
、Concatenate
或省略号。返回类型必须是单个类型。
如果将文字省略号 ...
作为参数列表给出,则表示具有任意参数列表的可调用对象都是可以接受的
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
现在支持 ParamSpec
和 Concatenate
。有关更多详细信息,请参阅 PEP 612。
另请参阅
ParamSpec
和 Concatenate
的文档提供了在 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
用户定义的泛型类型¶
用户定义的类可以定义为泛型类。
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]
形式的参数规范变量为参数表达式定义用户定义的泛型。该行为与上面描述的类型变量一致,因为类型模块将参数规范变量视为一种特殊的类型变量。唯一的例外是可以使用类型列表来替换 ParamSpec
。
>>> class Z[T, **P]: ... # T is a TypeVar; P is a ParamSpec
...
>>> Z[int, [dict, float]]
__main__.Z[int, [dict, float]]
也可以使用从 Generic
显式继承来创建基于 ParamSpec
的泛型类。在这种情况下,不使用 **
。
from typing import ParamSpec, Generic
P = ParamSpec('P')
class Z(Generic[P]):
...
TypeVar
和 ParamSpec
之间的另一个区别是,只有一个参数规范变量的泛型将接受 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__
,因为它们主要用于静态类型检查。
用户定义的泛型类可以将 ABC 作为基类,而不会发生元类冲突。不支持泛型元类。泛型参数化的结果会被缓存,并且 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")
名义子类型与结构子类型¶
最初,PEP 484 将 Python 静态类型系统定义为使用*名义子类型*。这意味着仅当 A
是 B
的子类时,才允许在需要类 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
隐式地视为 Sized
和 Iterable[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.AnyStr¶
一个 受约束的类型变量。
定义
AnyStr = TypeVar('AnyStr', str, bytes)
AnyStr
旨在用于可能接受str
或bytes
参数但不允许两者混合的函数。例如
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
请注意,尽管名称如此,
AnyStr
与Any
类型无关,也不意味着“任何字符串”。特别是,AnyStr
和str | 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!"
- 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 非常有用,在这些 API 中,任意的用户生成的字符串可能会产生问题。例如,上面两个生成类型检查器错误的情况可能容易受到 SQL 注入攻击。有关更多详细信息,请参阅 PEP 675。
在版本 3.11 中添加。
- typing.Never¶
- typing.NoReturn¶
Never
和NoReturn
表示 底类型,即没有成员的类型。它们可以用来指示一个函数永远不会返回,例如
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)
Never
和NoReturn
在类型系统中具有相同的含义,并且静态类型检查器对两者的处理方式相同。在版本 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
的实例,并且本身支持前向引用。请注意,虽然TypeAlias
和TypeAliasType
的用途和名称相似,但它们是不同的,后者不是前者的类型。目前没有计划删除TypeAlias
,但鼓励用户迁移到type
语句。
特殊形式¶
这些形式可以用作注释中的类型。它们都支持使用 []
进行订阅,但每个形式都有其独特的语法。
- 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.Concatenate¶
用于注释高阶函数的特殊形式。
Concatenate
可以与 Callable 和ParamSpec
结合使用,以注释添加、删除或转换另一个可调用对象的参数的高阶可调用对象。用法形式为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。3.8 版新增。
- 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.Required¶
特殊的类型构造函数,用于将
TypedDict
键标记为必需。这主要对
total=False
TypedDicts 有用。有关更多详细信息,请参阅TypedDict
和 PEP 655。在版本 3.11 中添加。
- typing.NotRequired¶
特殊的类型构造函数,用于将
TypedDict
键标记为可能缺失。有关更多详细信息,请参阅
TypedDict
和 PEP 655。在版本 3.11 中添加。
- 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 Annotated[int, ValueRange(3, 10), ctype("char")]
由使用注释的工具决定是否允许客户端向一个注释添加多个元数据元素,以及如何合并这些注释。
Annotated
必须至少使用两个参数进行下标(Annotated[int]
无效)元数据元素的顺序被保留,并且对相等性检查很重要
assert Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[ int, ctype("char"), ValueRange(3, 10) ]
嵌套的
Annotated
类型会被扁平化。元数据元素的顺序从最里面的注释开始assert Annotated[Annotated[int, ValueRange(3, 10)], 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] # NOT valid
这相当于
Annotated[T1, T2, T3, ..., Ann1]
其中
T1
、T2
等是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'>}
在运行时,可以通过
__metadata__
属性检索与Annotated
类型关联的元数据>>> from typing import Annotated >>> X = Annotated[int, "very", "important", "metadata"] >>> X typing.Annotated[int, 'very', 'important', 'metadata'] >>> X.__metadata__ ('very', 'important', 'metadata')
另请参阅
- PEP 593 - 灵活的函数和变量注释
将
Annotated
引入标准库的 PEP。
3.9 版新增。
- typing.TypeGuard¶
用于标记用户定义的类型保护函数的特殊类型构造函数。
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
告诉静态类型检查器,对于给定的函数返回值为布尔值。
如果返回值为
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
中的类型映射到第二个参数的类型(在cls
或self
之后)。简而言之,形式
def foo(arg: TypeA) -> TypeGuard[TypeB]: ...
表示如果foo(arg)
返回True
,则arg
从TypeA
缩小为TypeB
。注意
TypeB
不必是TypeA
的更窄形式 - 它甚至可以是更宽的形式。主要原因是为了允许诸如将list[object]
缩小为list[str]
之类的操作,即使后者不是前者的子类型,因为list
是不可变的。编写类型安全的类型守卫的责任留给用户。TypeGuard
也适用于类型变量。有关更多详细信息,请参阅 PEP 647。3.10 版新增。
- typing.Unpack¶
用于概念上标记对象已被解包的类型操作符。
例如,在 类型变量元组 上使用解包运算符
*
等效于使用Unpack
标记类型变量元组已被解包Ts = TypeVarTuple('Ts') tup: tuple[*Ts] # Effectively does: tup: tuple[Unpack[Ts]]
实际上,在
typing.TypeVarTuple
和builtins.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)¶
类型变量。
构造类型变量的首选方法是通过 泛型函数、泛型类 和 泛型类型别名 的专用语法
class Sequence[T]: # T is a TypeVar ...
此语法也可用于创建绑定和约束类型变量
class StrSequence[S: str]: # S is a TypeVar bound to 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=True
或contravariant=True
来显式标记手动创建的类型变量是协变的还是逆变的。默认情况下,手动创建的类型变量是不变的。有关更多详细信息,请参阅 PEP 484 和 PEP 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 或协议),甚至是类型的联合
# 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__¶
类型变量的边界(如果有)。
- __constraints__¶
一个元组,包含类型变量的约束(如果有)。
- class typing.TypeVarTuple(name)¶
类型变量元组。一种特殊形式的 类型变量,它支持可变泛型。
可以在 类型参数列表 中使用名称前的单个星号 (
*
) 声明类型变量元组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__¶
类型变量元组的名称。
在版本 3.11 中添加。
- class typing.ParamSpec(name, *, bound=None, covariant=False, contravariant=False)¶
参数规范变量。 类型变量 的一种特殊版本。
在 类型参数列表 中,可以使用两个星号 (
**
) 声明参数规范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
。但是,这会导致两个问题类型检查器无法对
inner
函数进行类型检查,因为*args
和**kwargs
必须键入Any
。在返回
inner
函数时,add_logging
装饰器的正文中可能需要cast()
,或者必须告诉静态类型检查器忽略return inner
。
- args¶
- kwargs¶
由于
ParamSpec
捕获了位置参数和关键字参数,因此可以使用P.args
和P.kwargs
将ParamSpec
拆分为其组成部分。P.args
表示给定调用中位置参数的元组,并且只能用于注释*args
。P.kwargs
表示给定调用中关键字参数与其值的映射,并且只能用于注释**kwargs
。 这两个属性都要求注释的参数在作用域内。 在运行时,P.args
和P.kwargs
分别是ParamSpecArgs
和ParamSpecKwargs
的实例。
- __name__¶
参数规范的名称。
使用
covariant=True
或contravariant=True
创建的参数规范变量可用于声明协变或逆变泛型类型。 与TypeVar
类似,也接受bound
参数。 但是,这些关键字的实际语义尚未确定。3.10 版新增。
注意
只有在全局作用域中定义的参数规范变量才能被序列化。
- typing.ParamSpecArgs¶
- typing.ParamSpecKwargs¶
ParamSpec
的参数和关键字参数属性。ParamSpec
的P.args
属性是ParamSpecArgs
的实例,而P.kwargs
是ParamSpecKwargs
的实例。 它们旨在用于运行时自省,对静态类型检查器没有特殊意义。在这两个对象上调用
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__ ()
其他特殊指令¶
这些函数和类不应直接用作注释。 它们的预期用途是作为创建和声明类型的构建块。
- 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 or lower 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 中更改: 添加了对泛型命名元组的支持。
- 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()
(稍后描述)装饰的协议类充当简单的运行时协议,仅检查给定属性的存在,而忽略其类型签名。协议类可以是泛型的,例如
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()
一起使用。当应用于非协议类时,这会引发TypeError
。这允许进行简单的结构检查,非常类似于collections.abc
中的“一招鲜” pony,例如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)
注意
runtime_checkable()
将仅检查所需方法或属性的存在,而不检查其类型签名或类型。例如,ssl.SSLObject
是一个类,因此它通过了针对 Callable 的issubclass()
检查。但是,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')
为了允许在不支持 PEP 526 的旧版本 Python 中使用此功能,
TypedDict
支持两种额外的等效语法形式使用文字
dict
作为第二个参数Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
使用关键字参数
Point2D = TypedDict('Point2D', x=int, y=int, label=str)
自 3.11 版起弃用,将在 3.13 版中删除: 关键字参数语法在 3.11 中已弃用,并将在 3.13 中删除。它也可能不受静态类型检查器的支持。
当任何键都不是有效的 标识符 时,例如因为它们是关键字或包含连字符,也应该使用函数语法。例如
# raises SyntaxError class Point2D(TypedDict): in: int # 'in' is a keyword x-y: int # name with hyphens # OK, functional syntax Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
默认情况下,所有键都必须出现在
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
可以省略任何键。类型检查器只支持字面量False
或True
作为total
参数的值。True
是默认值,它要求类体中定义的所有项都必须存在。可以使用
Required
将total=False
的TypedDict
的各个键标记为必需。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
有三个项:x
、y
和z
。它等效于以下定义class Point3D(TypedDict): x: int y: int z: int
除了
Generic
之外,TypedDict
不能从非TypedDict
类继承。例如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]
可以通过 annotations 字典(有关 annotations 最佳实践的更多信息,请参阅 Annotations 最佳实践)、
__total__
、__required_keys__
和__optional_keys__
对TypedDict
进行自省。- __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__
设置为True
的TypedDict
可能具有标记为NotRequired
的键,或者它可能继承自另一个total=False
的TypedDict
。因此,通常最好使用__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
参数有一个值,然后在另一个total
参数具有不同值的TypedDict
中继承它来完成的>>> 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
或者 annotations 以字符串形式给出,则在定义TypedDict
时不会评估 annotations。因此,__required_keys__
和__optional_keys__
所依赖的运行时自省可能无法正常工作,并且属性的值可能不正确。
有关使用
TypedDict
的更多示例和详细规则,请参阅 PEP 589。3.8 版新增。
版本 3.11 中的变化: 添加了对将单个键标记为
Required
或NotRequired
的支持。请参阅 PEP 655。版本 3.11 中的变化: 添加了对泛型
TypedDict
的支持。
协议¶
以下协议由 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__
,该方法在其返回类型中是协变的。
用于处理 IO 的 ABC¶
函数和装饰器¶
- 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)
这里,注释允许类型检查器推断最后一种情况永远不会执行,因为
arg
是int
或str
,并且这两种选择都被前面的情况覆盖了。如果类型检查器发现对
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
行为的装饰器。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
创建的类类似。例如,类型检查器将假定这些类具有接受id
和name
的__init__
方法。装饰的类、元类或函数可以接受以下布尔值参数,类型检查器将假定这些参数与它们在
@dataclasses.dataclass
装饰器上的效果相同:init
、eq
、order
、unsafe_hash
、frozen
、match_args
、kw_only
和slots
。这些参数的值(True
或False
)必须可以静态求值。可以使用
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
提供一个运行时回调,该回调返回字段的默认值。如果未指定
default
和default_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
。重载示例,它提供了比使用联合或类型变量所能表达的更精确的类型
@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
是否已被标记为最终的。如果被装饰的对象不支持设置属性,则装饰器将返回未更改的对象,而不引发异常。
- @typing.no_type_check¶
用于指示注释不是类型提示的装饰器。
这可以用作类或函数 装饰器。对于类,它递归地应用于该类中定义的所有方法和类(但不适用于在其超类或子类中定义的方法)。类型检查器将忽略带有此装饰器的函数或类中的所有注释。
@no_type_check
会原地修改被装饰的对象。
- @typing.no_type_check_decorator¶
修饰器,用于为另一个修饰器提供
no_type_check()
效果。这会将修饰器包装在另一个修饰器中,而该修饰器会将被修饰的函数包装在
no_type_check()
中。
- @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__
相同,但此函数会对注释字典进行以下更改:通过在 globalns、localns 和(如果适用)obj 的 类型参数 命名空间中评估前向引用(编码为字符串字面量或
ForwardRef
对象)来处理它们。如果未提供 globalns 或 localns,则会从 obj 推断出适当的命名空间字典。None
将替换为types.NoneType
。如果已将
@no_type_check
应用于 obj,则返回空字典。如果 obj 是类
C
,则该函数返回一个字典,该字典将 C 的基类的注释与 C 上的注释直接合并。这是通过遍历C.__mro__
并迭代组合__annotations__
字典来完成的。出现在 方法解析顺序 中较早的类上的注释始终优先于出现在方法解析顺序中较晚的类上的注释。该函数递归地将所有出现的
Annotated[T, ...]
替换为T
,除非 include_extras 设置为True
(有关更多信息,请参阅Annotated
)。
另请参阅
inspect.get_annotations()
,这是一个较低级别的函数,它更直接地返回注释。注意
如果 obj 的注释中的任何前向引用无法解析或不是有效的 Python 代码,则此函数将引发异常,例如
NameError
。例如,这可能发生在包含前向引用的导入 类型别名 中,或者在if TYPE_CHECKING
下导入的名称中。3.11 版更改: 以前,如果设置的默认值等于
None
,则会为函数和方法注释添加Optional[t]
。现在,注释将按原样返回。
- typing.get_origin(tp)¶
获取类型的未下标版本:对于
X[Y, Z, ...]
形式的类型对象,返回X
。如果
X
是内置类或collections
类的类型模块别名,它将被标准化为原始类。如果X
是ParamSpecArgs
或ParamSpecKwargs
的实例,则返回底层的ParamSpec
。对于不受支持的对象,返回None
。示例
assert get_origin(str) is None assert get_origin(Dict[str, int]) is dict assert get_origin(Union[int, str]) is Union 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, ...]
形式的类型对象,返回(Y, Z, ...)
。如果
X
是包含在另一个泛型类型中的联合或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.TYPE_CHECKING¶
一个特殊的常量,第三方静态类型检查器假定它为
True
。它在运行时为False
。用法
if TYPE_CHECKING: import expensive_mod def fun(arg: 'expensive_mod.SomeType') -> None: local_var: expensive_mod.AnotherType = other_fun()
第一个类型注解必须用引号括起来,使其成为“前向引用”,以便在解释器运行时隐藏对
expensive_mod
的引用。局部变量的类型注解不会被评估,因此第二个注解不需要用引号括起来。注意
如果使用了
from __future__ import annotations
,则注解不会在函数定义时进行评估。相反,它们将作为字符串存储在__annotations__
中。这使得不需要在注解周围使用引号(请参阅 PEP 563)。在 3.5.2 版本中添加。
已弃用的别名¶
此模块为预先存在的标准库类定义了几个已弃用的别名。这些别名最初包含在 typing 模块中,以便使用 []
对这些泛型类进行参数化。但是,当相应的预先存在的类在 Python 3.9 中得到增强以支持 []
时,这些别名就变得多余了(请参阅 PEP 585)。
从 Python 3.9 开始,这些冗余类型已被弃用。但是,虽然这些别名将来可能会被删除,但目前还没有计划删除它们。因此,解释器目前不会针对这些别名发出弃用警告。
如果将来决定删除这些已弃用的别名,则解释器将在删除之前至少发布两个版本的弃用警告。保证这些别名至少在 Python 3.14 之前会保留在 typing 模块中,并且不会发出弃用警告。
如果类型检查器正在检查的程序的目标 Python 版本为 3.9 或更高版本,则鼓励它们标记出已弃用类型的使用。
内置类型的别名¶
- class typing.Dict(dict, MutableMapping[KT, VT])¶
dict
的已弃用别名。请注意,要注释参数,最好使用抽象集合类型(例如
Mapping
),而不是使用dict
或typing.Dict
。此类型可以按如下方式使用
def count_words(text: str) -> Dict[str, int]: ...
3.9 版后已弃用:
builtins.dict
现在支持下标([]
)。请参阅 PEP 585 和 泛型别名类型。
- class typing.List(list, MutableSequence[T])¶
list
的已弃用别名。请注意,要注释参数,最好使用抽象集合类型(例如
Sequence
或Iterable
),而不是使用list
或typing.List
。此类型可以按如下方式使用
def vec2[T: (int, float)](x: T, y: T) -> List[T]: return [x, y] def keep_positives[T: (int, float)](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
),而不是使用set
或typing.Set
。3.9 版后已弃用:
builtins.set
现在支持下标([]
)。请参阅 PEP 585 和 泛型别名类型。
- class typing.FrozenSet(frozenset, AbstractSet[T_co])¶
builtins.frozenset
的已弃用别名。3.9 版后已弃用:
builtins.frozenset
现在支持下标([]
)。请参阅 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 和 泛型别名类型。
其他具体类型的别名¶
3.8 版后已弃用,将在 3.13 版中移除:
typing.io
命名空间已弃用,并将被移除。这些类型应直接从typing
导入。
- class typing.Pattern¶
- class typing.Match¶
与
re.compile()
和re.match()
的返回类型相对应的已弃用别名。这些类型(以及对应的函数)对于
AnyStr
是通用的。Pattern
可以被特化为Pattern[str]
或Pattern[bytes]
;Match
可以被特化为Match[str]
或Match[bytes]
。3.8 版后已弃用,将在 3.13 版中移除:
typing.re
命名空间已弃用,并将被移除。这些类型应该直接从typing
导入。
- class typing.Text¶
已弃用的
str
的别名。提供
Text
是为了给 Python 2 代码提供一条向前兼容的路径:在 Python 2 中,Text
是unicode
的别名。使用
Text
来表示一个值必须包含一个 Unicode 字符串,这种方式与 Python 2 和 Python 3 都兼容。def add_unicode_checkmark(text: Text) -> Text: return text + u' \u2713'
在 3.5.2 版本中添加。
3.11 版后已弃用: 不再支持 Python 2,并且大多数类型检查器也不再支持对 Python 2 代码进行类型检查。目前没有计划移除该别名,但鼓励用户使用
str
代替Text
。
collections.abc
中容器 ABC 的别名¶
- class typing.AbstractSet(Collection[T_co])¶
已弃用的
collections.abc.Set
的别名。3.9 版后已弃用:
collections.abc.Set
现在支持下标 ([]
)。参见 PEP 585 和 泛型别名类型。
- class typing.ByteString(Sequence[int])¶
此类型表示字节序列的类型
bytes
、bytearray
和memoryview
。3.9 版后已弃用,将在 3.14 版中移除: 建议使用
collections.abc.Buffer
,或类似bytes | bytearray | memoryview
的联合类型。
- 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
的别名。此类型可以按如下方式使用
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)¶
已弃用的
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
中异步 ABC 的别名¶
- class typing.Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType])¶
已弃用的
collections.abc.Coroutine
的别名。类型变量的方差和顺序对应于
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
3.5.3 版新增。
3.9 版后已弃用:
collections.abc.Coroutine
现在支持下标 ([]
)。 参见 PEP 585 和 泛型别名类型。
- class typing.AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType])¶
已弃用的
collections.abc.AsyncGenerator
的别名。异步生成器可以用泛型
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 和 泛型别名类型。
指向 collections.abc
中其他 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.Callable
和typing.Callable
的详细信息,请参阅 标注可调用对象。3.9 版后已弃用:
collections.abc.Callable
现在支持下标 ([]
)。 参见 PEP 585 和 泛型别名类型。在 3.10 版更改:
Callable
现在支持ParamSpec
和Concatenate
。 更多详细信息,请参阅 PEP 612。
- class typing.Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType])¶
已弃用的别名,指向
collections.abc.Generator
。可以使用泛型
Generator[YieldType, SendType, ReturnType]
对生成器进行标注。 例如def echo_round() -> Generator[int, float, str]: sent = yield 0 while sent >= 0: sent = yield round(sent) return 'Done'
请注意,与 typing 模块中的许多其他泛型不同,
Generator
的SendType
是逆变的,而不是协变或不变的。如果您的生成器只产生值,请将
SendType
和ReturnType
设置为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
的别名。自 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
ABC 的别名¶
- class typing.ContextManager(Generic[T_co])¶
已弃用的
contextlib.AbstractContextManager
的别名。3.5.4 版中添加。
自 3.9 版起弃用:
contextlib.AbstractContextManager
现在支持下标 ([]
)。请参阅 PEP 585 和 泛型别名类型。
- class typing.AsyncContextManager(Generic[T_co])¶
已弃用的
contextlib.AbstractAsyncContextManager
的别名。3.6.2 版中添加。
自 3.9 版起弃用:
contextlib.AbstractAsyncContextManager
现在支持下标 ([]
)。请参阅 PEP 585 和 泛型别名类型。
主要功能的弃用时间表¶
typing
中的某些功能已被弃用,并可能在 Python 的未来版本中被删除。下表总结了主要的弃用,以方便您参考。这可能会发生变化,并且并非所有弃用都列出。
功能 |
弃用于 |
预计删除 |
PEP/问题 |
---|---|---|---|
|
3.8 |
3.13 |
|
标准集合的 |
3.9 |
未定(有关更多信息,请参阅 已弃用的别名) |
|
3.9 |
3.14 |
||
3.11 |
未定 |
||
3.12 |
未定 |
||
3.12 |
未定 |