typing
— 类型提示支持¶
3.5 版本中新增。
源代码: Lib/typing.py
注解
Python 运行时不强制执行函数和变量类型注解。它们可以被第三方工具使用,例如类型检查器、IDE、代码检查器等。
此模块为类型提示提供运行时支持。
考虑下面的函数
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)
在运行时始终为 true。
创建 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
注释生成器和协程¶
可以使用泛型类型 Generator[YieldType, SendType, ReturnType]
来注释生成器。例如
def echo_round() -> Generator[int, float, str]:
sent = yield 0
while sent >= 0:
sent = yield round(sent)
return 'Done'
请注意,与标准库中的许多其他泛型类不同,Generator
的 SendType
的行为是逆变的,而不是协变或不变的。
SendType
和 ReturnType
参数默认为 None
。
def infinite_stream(start: int) -> Generator[int]:
while True:
yield start
start += 1
也可以显式设置这些类型。
def infinite_stream(start: int) -> Generator[int, None, None]:
while True:
yield start
start += 1
仅产生值的简单生成器也可以被标注为具有 Iterable[YieldType]
或 Iterator[YieldType]
的返回类型。
def infinite_stream(start: int) -> Iterator[int]:
while True:
yield start
start += 1
异步生成器的处理方式类似,但不期望有 ReturnType
类型参数 (AsyncGenerator[YieldType, SendType]
)。 SendType
参数的默认值为 None
,因此以下定义是等效的
async def infinite_stream(start: int) -> AsyncGenerator[int]:
while True:
yield start
start = await increment(start)
async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
while True:
yield start
start = await increment(start)
与同步情况一样,AsyncIterable[YieldType]
和 AsyncIterator[YieldType]
也可用。
async def infinite_stream(start: int) -> AsyncIterator[int]:
while True:
yield start
start = await increment(start)
可以使用 Coroutine[YieldType, SendType, ReturnType]
来标注协程。泛型参数对应于 Generator
的参数,例如
from collections.abc import Coroutine
c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere
x = c.send('hi') # Inferred type of 'x' is list[str]
async def bar() -> None:
y = await c # Inferred type of 'y' is int
用户定义的泛型类型¶
用户定义的类可以被定义为泛型类。
from logging import Logger
class LoggedVar[T]:
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message)
此语法表示类 LoggedVar
是围绕单个类型变量 T
参数化的。这也使得 T
在类主体中作为类型有效。
泛型类隐式继承自 Generic
。为了与 Python 3.11 及更低版本兼容,也可以显式地从 Generic
继承以指示泛型类
from typing import TypeVar, Generic
T = TypeVar('T')
class LoggedVar(Generic[T]):
...
泛型类具有 __class_getitem__()
方法,这意味着它们可以在运行时进行参数化 (例如,下面的 LoggedVar[int]
)
from collections.abc import Iterable
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
for var in vars:
var.set(0)
一个泛型类型可以有任意数量的类型变量。TypeVar
的所有变体都允许作为泛型类型的参数
from typing import TypeVar, Generic, Sequence
class WeirdTrio[T, B: Sequence[bytes], S: (int, str)]:
...
OldT = TypeVar('OldT', contravariant=True)
OldB = TypeVar('OldB', bound=Sequence[bytes], covariant=True)
OldS = TypeVar('OldS', int, str)
class OldWeirdTrio(Generic[OldT, OldB, OldS]):
...
Generic
的每个类型变量参数都必须不同。因此,这是无效的
from typing import TypeVar, Generic
...
class Pair[M, M]: # SyntaxError
...
T = TypeVar('T')
class Pair(Generic[T, T]): # INVALID
...
泛型类也可以从其他类继承
from collections.abc import Sized
class LinkedList[T](Sized):
...
从泛型类继承时,某些类型参数可以被固定
from collections.abc import Mapping
class MyDict[T](Mapping[str, T]):
...
在这种情况下,MyDict
只有一个参数 T
。
使用泛型类而不指定类型参数假定每个位置都是 Any
。在以下示例中,MyIterable
不是泛型的,但隐式继承自 Iterable[Any]
from collections.abc import Iterable
class MyIterable(Iterable): # Same as Iterable[Any]
...
还支持用户定义的泛型类型别名。示例
from collections.abc import Iterable
type Response[S] = Iterable[S] | int
# Return type here is same as Iterable[str] | int
def response(query: str) -> Response[str]:
...
type Vec[T] = Iterable[tuple[T, T]]
def inproduct[T: (int, float, complex)](v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
return sum(x*y for x, y in v)
为了向后兼容,也可以通过简单的赋值创建泛型类型别名
from collections.abc import Iterable
from typing import TypeVar
S = TypeVar("S")
Response = Iterable[S] | int
在 3.7 版本中更改: Generic
不再具有自定义元类。
在 3.12 版本中更改: 对泛型和类型别名的语法支持在 3.12 版本中是新增的。以前,泛型类必须显式地从 Generic
继承或在其基类之一中包含类型变量。
还支持通过参数规范变量 [**P]
形式的用户定义的参数表达式的泛型。其行为与上面描述的类型变量一致,因为 typing 模块将参数规范变量视为一种专门的类型变量。唯一的例外是,可以使用类型列表来替换 ParamSpec
>>> class Z[T, **P]: ... # T is a TypeVar; P is a ParamSpec
...
>>> Z[int, [dict, float]]
__main__.Z[int, [dict, float]]
也可以使用显式继承自 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")
标称子类型 vs 结构子类型¶
最初,PEP 484 将 Python 静态类型系统定义为使用标称子类型。这意味着,当且仅当 A
是 B
的子类时,才允许使用类 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
视为 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 非常有用。 例如,上面产生类型检查器错误的两个案例可能容易受到 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 版本中更改: 现在可以使用
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.ReadOnly¶
一个特殊的类型构造,用于将
TypedDict
的项标记为只读。例如
class Movie(TypedDict): title: ReadOnly[str] year: int def mutate_movie(m: Movie) -> None: m["year"] = 1999 # allowed m["title"] = "The Matrix" # typechecker error
此属性没有运行时检查。
更多详细信息,请参阅
TypedDict
和 PEP 705。在 3.13 版本中新增。
- typing.Annotated¶
特殊的类型形式,用于向注解添加特定于上下文的元数据。
使用注解
Annotated[T, x]
将元数据x
添加到给定的类型T
。使用Annotated
添加的元数据可以被静态分析工具或在运行时使用。在运行时,元数据存储在__metadata__
属性中。如果库或工具遇到注解
Annotated[T, x]
并且没有针对元数据的特殊逻辑,则应忽略该元数据,并将该注解简单地视为T
。因此,Annotated
对于希望在 Python 的静态类型系统之外使用注解的代码很有用。使用
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')
在运行时,如果您想检索
Annotated
包裹的原始类型,请使用__origin__
属性>>> from typing import Annotated, get_origin >>> Password = Annotated[str, "secret"] >>> Password.__origin__ <class 'str'>
请注意,使用
get_origin()
将返回Annotated
本身>>> get_origin(Password) typing.Annotated
参见
- PEP 593 - 灵活的函数和变量注解
将
Annotated
引入标准库的 PEP。
在 3.9 版本中新增。
- typing.TypeIs¶
用于标记用户定义的类型谓词函数的特殊类型构造。
TypeIs
可用于注解用户定义的类型谓词函数的返回类型。TypeIs
只接受单个类型参数。在运行时,以这种方式标记的函数应该返回一个布尔值,并且至少接受一个位置参数。TypeIs
旨在受益于类型缩小 – 静态类型检查器使用的一种技术,用于确定程序代码流中表达式的更精确类型。通常,类型缩小是通过分析条件代码流并将缩小应用于代码块来完成的。这里的条件表达式有时被称为“类型谓词”def is_str(val: str | float): # "isinstance" type predicate if isinstance(val, str): # Type of ``val`` is narrowed to ``str`` ... else: # Else, type of ``val`` is narrowed to ``float``. ...
有时,将用户定义的布尔函数用作类型谓词会很方便。这样的函数应使用
TypeIs[...]
或TypeGuard
作为其返回类型,以提醒静态类型检查器注意此意图。TypeIs
通常比TypeGuard
具有更直观的行为,但是当输入和输出类型不兼容时(例如,从list[object]
到list[int]
)或者当函数没有为缩小类型的的所有实例返回True
时,它不能使用。使用
-> TypeIs[NarrowedType]
告诉静态类型检查器,对于给定的函数返回值是一个布尔值。
如果返回值是
True
,则其参数的类型是参数的原始类型和NarrowedType
的交集。如果返回值是
False
,则其参数的类型将被缩小以排除NarrowedType
。
例如
from typing import assert_type, final, TypeIs class Parent: pass class Child(Parent): pass @final class Unrelated: pass def is_parent(val: object) -> TypeIs[Parent]: return isinstance(val, Parent) def run(arg: Child | Unrelated): if is_parent(arg): # Type of ``arg`` is narrowed to the intersection # of ``Parent`` and ``Child``, which is equivalent to # ``Child``. assert_type(arg, Child) else: # Type of ``arg`` is narrowed to exclude ``Parent``, # so only ``Unrelated`` is left. assert_type(arg, Unrelated)
TypeIs
内的类型必须与函数参数的类型一致;如果不是,则静态类型检查器将引发错误。编写错误的TypeIs
函数可能会导致类型系统中不健全的行为;用户有责任以类型安全的方式编写此类函数。如果
TypeIs
函数是类方法或实例方法,则TypeIs
中的类型映射到第二个参数的类型(在cls
或self
之后)。简而言之,形式为
def foo(arg: TypeA) -> TypeIs[TypeB]: ...
的函数,意味着如果foo(arg)
返回True
,则arg
是TypeB
的实例;如果返回False
,则不是TypeB
的实例。TypeIs
也适用于类型变量。更多信息,请参阅 PEP 742 (使用TypeIs
缩小类型)。在 3.13 版本中新增。
- typing.TypeGuard¶
用于标记用户定义的类型谓词函数的特殊类型构造。
类型谓词函数是用户定义的函数,用于返回其参数是否为特定类型的实例。
TypeGuard
的工作方式类似于TypeIs
,但对类型检查行为有细微的不同影响(见下文)。使用
-> TypeGuard
告诉静态类型检查器,对于给定的函数返回值是一个布尔值。
如果返回值是
True
,则其参数的类型是TypeGuard
内部的类型。
TypeGuard
也适用于类型变量。更多详细信息,请参阅 PEP 647。例如
def is_str_list(val: list[object]) -> TypeGuard[list[str]]: '''Determines whether all objects in the list are strings''' return all(isinstance(x, str) for x in val) def func1(val: list[object]): if is_str_list(val): # Type of ``val`` is narrowed to ``list[str]``. print(" ".join(val)) else: # Type of ``val`` remains as ``list[object]``. print("Not a list of strings!")
TypeIs
和TypeGuard
在以下方面有所不同TypeIs
要求缩小的类型是输入类型的子类型,而TypeGuard
则不需要。主要原因是允许诸如将list[object]
缩小为list[str]
之类的情况,即使后者不是前者的子类型,因为list
是不变的。当
TypeGuard
函数返回True
时,类型检查器会将变量的类型缩小为精确的TypeGuard
类型。当TypeIs
函数返回True
时,类型检查器可以推断出更精确的类型,即将变量的先前已知类型与TypeIs
类型相结合。(从技术上讲,这被称为交叉类型。)当
TypeGuard
函数返回False
时,类型检查器根本无法缩小变量的类型。当TypeIs
函数返回False
时,类型检查器可以将变量的类型缩小为排除TypeIs
类型。
在 3.10 版本中添加。
- typing.Unpack¶
用于从概念上标记对象已被解包的类型操作符。
例如,对 类型变量元组 使用解包操作符
*
等效于使用Unpack
来标记类型变量元组已被解包Ts = TypeVarTuple('Ts') tup: tuple[*Ts] # Effectively does: tup: tuple[Unpack[Ts]]
实际上,在
typing.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, default=typing.NoDefault)¶
类型变量。
构造类型变量的首选方法是通过泛型函数、泛型类 和 泛型类型别名的专用语法
class Sequence[T]: # T is a TypeVar ...
此语法还可以用于创建有界和约束类型变量
class StrSequence[S: str]: # S is a TypeVar with a `str` upper bound; ... # we can say that S is "bounded by `str`" class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes ...
但是,如果需要,也可以手动构造可重用的类型变量,如下所示
T = TypeVar('T') # Can be anything S = TypeVar('S', bound=str) # Can be any subtype of str A = TypeVar('A', str, bytes) # Must be exactly str or bytes
类型变量的存在主要是为了方便静态类型检查器。它们用作泛型类型以及泛型函数和类型别名定义的参数。有关泛型类型的更多信息,请参阅
Generic
。泛型函数的工作方式如下def repeat[T](x: T, n: int) -> Sequence[T]: """Return a list containing n references to x.""" return [x]*n def print_capitalized[S: str](x: S) -> S: """Print x capitalized, and return x.""" print(x.capitalize()) return x def concatenate[A: (str, bytes)](x: A, y: A) -> A: """Add two strings or bytes objects together.""" return x + y
请注意,类型变量可以是有界的、受约束的或两者都不是,但不能同时有界和受约束。
当通过 类型参数语法 创建类型变量或传递
infer_variance=True
时,类型检查器会推断类型变量的变体。可以通过传递covariant=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 或 Protocol)甚至类型联合
# Can be anything with an __abs__ method def print_abs[T: SupportsAbs](arg: T) -> None: print("Absolute value:", abs(arg)) U = TypeVar('U', bound=str|bytes) # Can be any subtype of the union str|bytes V = TypeVar('V', bound=SupportsAbs) # Can be anything with an __abs__ method
但是,使用约束类型变量意味着
TypeVar
只能始终解析为给定的约束之一a = concatenate('one', 'two') reveal_type(a) # revealed type is str b = concatenate(StringSubclass('one'), StringSubclass('two')) reveal_type(b) # revealed type is str, despite StringSubclass being passed in c = concatenate('one', b'two') # error: type variable 'A' can be either str or bytes in a function call, but not both
在运行时,
isinstance(x, T)
将引发TypeError
。- __name__¶
类型变量的名称。
- __covariant__¶
类型变量是否已被显式标记为协变。
- __contravariant__¶
类型变量是否已被显式标记为逆变。
- __infer_variance__¶
类型检查器是否应推断类型变量的变体。
在 3.12 版本中添加。
- __bound__¶
类型变量的上界(如果有)。
- __constraints__¶
一个元组,包含类型变量的约束(如果有)。
- __default__¶
类型变量的默认值,如果没有默认值,则为
typing.NoDefault
。在 3.13 版本中新增。
- has_default()¶
返回类型变量是否具有默认值。这等效于检查
__default__
是否不是typing.NoDefault
单例,但它不会强制计算延迟计算的默认值。在 3.13 版本中新增。
3.13 版本更改: 添加了对默认值的支持。
- class typing.TypeVarTuple(name, *, default=typing.NoDefault)¶
类型变量元组。一种特殊的类型变量形式,可实现可变泛型。
可以使用名称前的一个星号(
*
)在类型参数列表中声明类型变量元组。def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]: return (*tup[1:], tup[0])
或者通过显式调用
TypeVarTuple
构造函数来声明。T = TypeVar("T") Ts = TypeVarTuple("Ts") def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]: return (*tup[1:], tup[0])
普通类型变量允许使用单个类型进行参数化。相反,类型变量元组允许通过充当包裹在元组中的任意数量的类型变量来实现使用任意数量的类型进行参数化。例如:
# T is bound to int, Ts is bound to () # Return value is (1,), which has type tuple[int] move_first_element_to_last(tup=(1,)) # T is bound to int, Ts is bound to (str,) # Return value is ('spam', 1), which has type tuple[str, int] move_first_element_to_last(tup=(1, 'spam')) # T is bound to int, Ts is bound to (str, float) # Return value is ('spam', 3.0, 1), which has type tuple[str, float, int] move_first_element_to_last(tup=(1, 'spam', 3.0)) # This fails to type check (and fails at runtime) # because tuple[()] is not compatible with tuple[T, *Ts] # (at least one element is required) move_first_element_to_last(tup=())
请注意在
tuple[T, *Ts]
中使用了拆包运算符*
。从概念上讲,您可以将Ts
视为类型变量的元组(T1, T2, ...)
。tuple[T, *Ts]
然后会变成tuple[T, *(T1, T2, ...)]
,这等效于tuple[T, T1, T2, ...]
。(请注意,在旧版本的 Python 中,您可能会看到使用Unpack
来编写此内容,如Unpack[Ts]
。)类型变量元组必须始终被解包。这有助于将类型变量元组与普通类型变量区分开来。
x: Ts # Not valid x: tuple[Ts] # Not valid x: tuple[*Ts] # The correct way to do it
类型变量元组可以在与普通类型变量相同的上下文中使用。例如,在类定义、参数和返回类型中。
class Array[*Shape]: def __getitem__(self, key: tuple[*Shape]) -> float: ... def __abs__(self) -> "Array[*Shape]": ... def get_shape(self) -> tuple[*Shape]: ...
类型变量元组可以与普通类型变量愉快地组合使用。
class Array[DType, *Shape]: # This is fine pass class Array2[*Shape, DType]: # This would also be fine pass class Height: ... class Width: ... float_array_1d: Array[float, Height] = Array() # Totally fine int_array_2d: Array[int, Height, Width] = Array() # Yup, fine too
但是,请注意,在单个类型参数或类型参数列表中最多只能出现一个类型变量元组。
x: tuple[*Ts, *Ts] # Not valid class Array[*Shape, *Shape]: # Not valid pass
最后,可以解包类型变量元组作为
*args
的类型注释。def call_soon[*Ts]( callback: Callable[[*Ts], None], *args: *Ts ) -> None: ... callback(*args)
与
*args
的非解包注释(例如,*args: int
,它指定所有参数都是int
)相反,*args: *Ts
允许引用*args
中各个参数的类型。在这里,这允许我们确保传递给call_soon
的*args
的类型与callback
的(位置)参数的类型匹配。有关类型变量元组的更多详细信息,请参阅PEP 646。
- __name__¶
类型变量元组的名称。
- __default__¶
类型变量元组的默认值,如果没有默认值,则为
typing.NoDefault
。在 3.13 版本中新增。
- has_default()¶
返回类型变量元组是否具有默认值。这等效于检查
__default__
是否不是typing.NoDefault
单例,但它不会强制计算延迟计算的默认值。在 3.13 版本中新增。
在 3.11 版本中添加。
3.13 版本更改: 添加了对默认值的支持。
- class typing.ParamSpec(name, *, bound=None, covariant=False, contravariant=False, default=typing.NoDefault)¶
参数规格变量。一种特殊的类型变量版本。
在类型参数列表中,可以使用两个星号(
**
)声明参数规范。type IntFunc[**P] = Callable[P, int]
为了与 Python 3.11 及更早版本兼容,也可以按以下方式创建
ParamSpec
对象:P = ParamSpec('P')
参数规格变量主要用于静态类型检查器。它们用于将一个可调用对象的参数类型转发到另一个可调用对象,这是一种常见于高阶函数和装饰器中的模式。它们仅在
Concatenate
中,或作为Callable
的第一个参数,或作为用户定义的泛型的参数时有效。有关泛型类型的更多信息,请参阅Generic
。例如,为了向函数添加基本日志记录,可以创建一个装饰器
add_logging
来记录函数调用。参数规格变量告诉类型检查器,传递给装饰器的可调用对象和它返回的新可调用对象具有相互依赖的类型参数。from collections.abc import Callable import logging def add_logging[T, **P](f: Callable[P, T]) -> Callable[P, T]: '''A type-safe decorator to add logging to a function.''' def inner(*args: P.args, **kwargs: P.kwargs) -> T: logging.info(f'{f.__name__} was called') return f(*args, **kwargs) return inner @add_logging def add_two(x: float, y: float) -> float: '''Add two numbers together.''' return x + y
如果没有
ParamSpec
,以前注释此内容的最简单方法是使用带有上限Callable[..., Any]
的TypeVar
。但是,这会导致两个问题:类型检查器无法类型检查
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__¶
参数规范的名称。
- __default__¶
参数规范的默认值,或者如果没有默认值,则为
typing.NoDefault
。在 3.13 版本中新增。
- has_default()¶
返回参数规范是否具有默认值。这等效于检查
__default__
是否不是typing.NoDefault
单例,只是它不会强制评估 延迟评估 的默认值。在 3.13 版本中新增。
使用
covariant=True
或contravariant=True
创建的参数规范变量可用于声明协变或逆变泛型类型。bound
参数也被接受,类似于TypeVar
。但是,这些关键字的实际语义尚未确定。在 3.10 版本中添加。
3.13 版本更改: 添加了对默认值的支持。
注解
只有在全局作用域中定义的参数规范变量才能被 pickle 序列化。
参见
PEP 612 – 参数规范变量(引入
ParamSpec
和Concatenate
的 PEP)
- 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 T = TypeVar("T") class Group(NamedTuple, Generic[T]): key: T group: list[T] # A functional syntax is also supported Employee = NamedTuple('Employee', [('name', str), ('id', int)])
在 3.6 版本中更改: 增加了对 PEP 526 变量注解语法的支持。
在 3.6.1 版本中更改: 增加了对默认值、方法和文档字符串的支持。
在 3.8 版本中更改:
_field_types
和__annotations__
属性现在是常规字典,而不是OrderedDict
的实例。在 3.9 版本中更改: 删除了
_field_types
属性,而使用了更标准的__annotations__
属性,该属性具有相同的信息。在 3.11 版本中更改: 增加了对泛型命名元组的支持。
自 3.13 版本起已弃用,将在 3.15 版本中删除: 用于创建 NamedTuple 类的未记录的关键字参数语法 (
NT = NamedTuple("NT", x=int)
) 已弃用,将在 3.15 中禁止使用。请改用基于类的语法或函数式语法。自 3.13 版本起已弃用,将在 3.15 版本中移除:当使用函数式语法创建 NamedTuple 类时,不向 ‘fields’ 参数传递值(
NT = NamedTuple("NT")
)已被弃用。向 ‘fields’ 参数传递None
(NT = NamedTuple("NT", None)
)也被弃用。这两个用法将在 Python 3.15 中被禁止。要创建具有 0 个字段的 NamedTuple 类,请使用class NT(NamedTuple): pass
或NT = NamedTuple("NT", [])
。
- class typing.NewType(name, tp)¶
用于创建低开销不同类型的辅助类。
类型检查器将
NewType
视为不同的类型。但是,在运行时,调用NewType
会返回其参数,且不进行任何更改。用法
UserId = NewType('UserId', int) # Declare the NewType "UserId" first_user = UserId(1) # "UserId" returns the argument unchanged at runtime
- __module__¶
定义新类型的模块。
- __name__¶
新类型的名称。
- __supertype__¶
新类型所基于的类型。
在 3.5.2 版本中添加。
在 3.10 版本中更改:
NewType
现在是一个类而不是一个函数。
- class typing.Protocol(Generic)¶
协议类的基类。
协议类的定义方式如下
class Proto(Protocol): def meth(self) -> int: ...
此类主要与识别结构子类型(静态鸭子类型)的静态类型检查器一起使用,例如
class C: def meth(self) -> int: return 0 def func(x: Proto) -> int: return x.meth() func(C()) # Passes static type check
有关更多详细信息,请参见 PEP 544。使用
runtime_checkable()
(稍后描述)修饰的协议类充当简单的运行时协议,仅检查给定属性的存在,而忽略其类型签名。协议类可以是泛型的,例如
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
中诸如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')
创建
TypedDict
的另一种方法是使用函数调用语法。第二个参数必须是字面量的dict
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
此函数语法允许定义无效的 标识符,例如,因为它们是关键字或包含连字符
# raises SyntaxError class Point2D(TypedDict): in: int # 'in' is a keyword x-y: int # name with hyphens # 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
TypedDict
不能从非TypedDict
类继承,除了Generic
。例如class X(TypedDict): x: int class Y(TypedDict): y: int class Z(object): pass # A non-TypedDict class class XY(X, Y): pass # OK class XZ(X, Z): pass # raises TypeError
TypedDict
可以是泛型的class Group[T](TypedDict): key: T group: list[T]
要创建与 Python 3.11 或更低版本兼容的泛型
TypedDict
,请显式地从Generic
继承T = TypeVar("T") class Group(TypedDict, Generic[T]): key: T group: list[T]
可以通过 annotations dicts(有关注释最佳实践的更多信息,请参见 注释最佳实践)、
__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。例如,将__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
中声明必需键和非必需键。这通过声明一个带有total
参数的一个值的TypedDict
,然后在另一个带有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
或者如果注解以字符串形式给出,则在定义TypedDict
时不会评估注解。因此,__required_keys__
和__optional_keys__
所依赖的运行时内省可能无法正常工作,并且属性的值可能不正确。
对
ReadOnly
的支持反映在以下属性中有关使用
TypedDict
的更多示例和详细规则,请参阅 PEP 589。在 3.8 版本中添加。
3.11 版本更改: 添加了将单个键标记为
Required
或NotRequired
的支持。请参阅 PEP 655。3.11 版本更改: 添加了对泛型
TypedDict
的支持。3.13 版本更改: 删除了使用关键字参数方法创建
TypedDict
的支持。3.13 版本更改: 添加了对
ReadOnly
限定符的支持。3.13 版本起已弃用,将在 3.15 版本中删除: 当使用函数语法创建 TypedDict 类时,未能将值传递给 'fields' 参数(
TD = TypedDict("TD")
)已被弃用。将None
传递给 'fields' 参数(TD = TypedDict("TD", None)
)也被弃用。这两个操作将在 Python 3.15 中被禁止。要创建具有 0 个字段的 TypedDict 类,请使用class TD(TypedDict): pass
或TD = TypedDict("TD", {})
。
协议¶
typing 模块提供了以下协议。所有协议都使用 @runtime_checkable
装饰。
- class typing.SupportsAbs¶
一个 ABC(抽象基类),带有一个抽象方法
__abs__
,其返回类型是协变的。
- class typing.SupportsBytes¶
一个 ABC,带有一个抽象方法
__bytes__
。
- class typing.SupportsComplex¶
一个 ABC,带有一个抽象方法
__complex__
。
- class typing.SupportsFloat¶
一个 ABC,带有一个抽象方法
__float__
。
- class typing.SupportsIndex¶
一个 ABC,带有一个抽象方法
__index__
。在 3.8 版本中添加。
- class typing.SupportsInt¶
一个 ABC,带有一个抽象方法
__int__
。
- class typing.SupportsRound¶
一个 ABC,带有一个抽象方法
__round__
,其返回类型是协变的。
用于处理 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
类型检查器将以类似于使用
@dataclasses.dataclass
创建的类的方式处理上面定义的CustomerModel
类。 例如,类型检查器将假定这些类具有接受id
和name
的__init__
方法。被装饰的类、元类或函数可能接受以下 bool 参数,类型检查器会假定这些参数具有与它们在
@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
值。别名
为该字段提供一个替代名称。此替代名称用于合成的
__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()
中的东西来包装该装饰器。自 3.13 版本起已弃用,将在 3.15 版本中删除:没有类型检查器添加过对
@no_type_check_decorator
的支持。因此,它已弃用,将在 Python 3.15 中删除。
- @typing.override¶
指示子类中的方法旨在覆盖超类中的方法或属性的装饰器。
如果使用
@override
修饰的方法实际上没有覆盖任何内容,类型检查器应发出错误。这有助于防止在更改基类而没有对子类进行等效更改时可能发生的错误。例如
class Base: def log_status(self) -> None: ... class Sub(Base): @override def log_status(self) -> None: # Okay: overrides Base.log_status ... @override def done(self) -> None: # Error reported by type checker ...
此属性没有运行时检查。
该装饰器将尝试在修饰的对象上设置
__override__
属性为True
。因此,可以在运行时使用类似if getattr(obj, "__override__", False)
的检查来确定对象obj
是否被标记为覆盖。如果修饰的对象不支持设置属性,则该装饰器将返回未更改的对象,而不会引发异常。有关更多详细信息,请参阅 PEP 698。
在 3.12 版本中添加。
- @typing.type_check_only¶
用于将类或函数标记为在运行时不可用的装饰器。
此装饰器本身在运行时不可用。它主要用于标记类型存根文件中定义的类,如果实现返回私有类的实例
@type_check_only class Response: # private or not available at runtime code: int def get_header(self, name: str) -> str: ... def fetch_response() -> Response: ...
请注意,不建议返回私有类的实例。通常最好使此类公开。
自省助手¶
- typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False)¶
返回包含函数、方法、模块或类对象的类型提示的字典。
这通常与
obj.__annotations__
相同,但此函数对注解字典进行了以下更改编码为字符串字面量或
ForwardRef
对象的前向引用通过在 globalns、localns 和(如果适用)obj 的类型参数命名空间中计算它们来处理。如果未给出 globalns 或 localns,则从 obj 推断出适当的命名空间字典。None
将被替换为types.NoneType
。如果
@no_type_check
已应用于 obj,则返回一个空字典。如果 obj 是一个类
C
,该函数返回一个字典,该字典合并了来自C
的基类的注解以及直接在C
上的注解。这是通过遍历C.__mro__
并迭代地组合__annotations__
字典来完成的。在 方法解析顺序 中较早出现的类上的注解始终优先于方法解析顺序中较晚出现的类上的注解。除非将 include_extras 设置为
True
(有关更多信息,请参见Annotated
),否则该函数会递归地将所有出现的Annotated[T, ...]
替换为T
。
另请参见
inspect.get_annotations()
,这是一个更低级别的函数,它可以更直接地返回注解。注解
如果 obj 的注解中的任何前向引用无法解析或不是有效的 Python 代码,则此函数将引发异常,例如
NameError
。例如,当导入的 类型别名 包含前向引用,或者使用if TYPE_CHECKING
导入的名称时,可能会发生这种情况。在 3.11 版本中更改: 以前,如果设置了等于
None
的默认值,则为函数和方法注解添加Optional[t]
。现在,注解将按原样返回。
- typing.get_origin(tp)¶
获取类型的未订阅版本:对于
X[Y, Z, ...]
形式的 typing 对象,返回X
。如果
X
是内置类或collections
类的 typing 模块别名,则它将被标准化为原始类。如果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 assert get_origin(Annotated[str, "metadata"]) is Annotated P = ParamSpec('P') assert get_origin(P.args) is P assert get_origin(P.kwargs) is P
在 3.8 版本中添加。
- typing.get_args(tp)¶
获取执行所有替换的类型参数:对于
X[Y, Z, ...]
形式的 typing 对象,返回(Y, Z, ...)
。如果
X
是一个联合类型或包含在另一个泛型类型中的Literal
,则由于类型缓存,(Y, Z, ...)
的顺序可能与原始参数[Y, Z, ...]
的顺序不同。对于不支持的对象,返回()
。示例
assert get_args(int) == () assert get_args(Dict[int, str]) == (int, str) assert get_args(Union[int, str]) == (int, str)
在 3.8 版本中添加。
- typing.get_protocol_members(tp)¶
返回在
Protocol
中定义的成员集合。>>> from typing import Protocol, get_protocol_members >>> class P(Protocol): ... def a(self) -> str: ... ... b: int >>> get_protocol_members(P) == frozenset({'a', 'b'}) True
对于不是 Protocol 的参数,引发
TypeError
。在 3.13 版本中新增。
- typing.is_protocol(tp)¶
确定类型是否为
Protocol
。例如
class P(Protocol): def a(self) -> str: ... b: int is_protocol(P) # => True is_protocol(int) # => False
在 3.13 版本中新增。
- typing.is_typeddict(tp)¶
检查类型是否为
TypedDict
。例如
class Film(TypedDict): title: str year: int assert is_typeddict(Film) assert not is_typeddict(list | str) # TypedDict is a factory for creating typed dicts, # not a typed dict itself assert not is_typeddict(TypedDict)
在 3.10 版本中添加。
- class typing.ForwardRef¶
用于字符串前向引用的内部类型表示的类。
例如,
List["SomeClass"]
隐式转换为List[ForwardRef("SomeClass")]
。ForwardRef
不应由用户实例化,但可由内省工具使用。注解
PEP 585 泛型类型(例如
list["SomeClass"]
)不会隐式转换为list[ForwardRef("SomeClass")]
,因此不会自动解析为list[SomeClass]
。在 3.7.4 版本中添加。
- typing.NoDefault¶
一个哨兵对象,用于指示类型参数没有默认值。例如
>>> T = TypeVar("T") >>> T.__default__ is typing.NoDefault True >>> S = TypeVar("S", default=None) >>> S.__default__ is None True
在 3.13 版本中新增。
常量¶
- typing.TYPE_CHECKING¶
一个特殊常量,第三方静态类型检查器假定其为
True
。它在运行时为False
。用法
if TYPE_CHECKING: 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 开始,冗余类型已被弃用。但是,虽然别名可能会在某个时候被删除,但目前尚无删除这些别名的计划。因此,解释器目前不会针对这些别名发出弃用警告。
如果在某个时候决定删除这些已弃用的别名,则解释器将在删除前至少两个版本发出弃用警告。别名保证在 typing 模块中保留,直到至少 Python 3.14,而不会发出弃用警告。
如果类型检查器检查的程序的目标 Python 最低版本为 3.9 或更高版本,则建议类型检查器标记已弃用类型的使用。
内置类型的别名¶
- class typing.Dict(dict, MutableMapping[KT, VT])¶
已弃用
dict
的别名。请注意,要注解参数,最好使用抽象集合类型(例如
Mapping
),而不是使用dict
或typing.Dict
。在 3.9 版本中已弃用:
builtins.dict
现在支持下标 ([]
)。请参阅 PEP 585 和 泛型别名类型。
- class typing.List(list, MutableSequence[T])¶
已弃用的
list
的别名。请注意,为了注释参数,最好使用抽象集合类型,例如
Sequence
或Iterable
,而不是使用list
或typing.List
。3.9 版本起已弃用:
builtins.list
现在支持下标 ([]
)。请参阅 PEP 585 和 通用别名类型。
- class typing.Set(set, MutableSet[T])¶
已弃用的
builtins.set
的别名。请注意,为了注释参数,最好使用抽象集合类型,例如
collections.abc.Set
,而不是使用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 和 通用别名类型。
其他具体类型的别名¶
- class typing.Pattern¶
- class typing.Match¶
与
re.compile()
和re.match()
的返回类型对应的已弃用别名。这些类型(以及相应的函数)在
AnyStr
上是泛型的。Pattern
可以专门化为Pattern[str]
或Pattern[bytes]
;Match
可以专门化为Match[str]
或Match[bytes]
。
- class typing.Text¶
已弃用的
str
别名。提供
Text
是为了为 Python 2 代码提供向前兼容的路径:在 Python 2 中,Text
是unicode
的别名。使用
Text
来表示一个值必须包含一个与 Python 2 和 Python 3 都兼容的 Unicode 字符串。def add_unicode_checkmark(text: Text) -> Text: return text + u' \u2713'
在 3.5.2 版本中添加。
3.11 版本起已弃用: Python 2 不再受支持,并且大多数类型检查器也不再支持类型检查 Python 2 代码。目前没有计划删除此别名,但鼓励用户使用
str
而不是Text
。
collections.abc
中容器 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
别名。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
。有关在类型注解中使用
collections.abc.Coroutine
和typing.Coroutine
的详细信息,请参阅 注解生成器和协程。在 3.5.3 版本中添加。
3.9 版本起已弃用:
collections.abc.Coroutine
现在支持下标操作 ([]
)。参见 PEP 585 和 泛型别名类型。
- class typing.AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType])¶
已弃用的别名,指向
collections.abc.AsyncGenerator
。有关在类型注解中使用
collections.abc.AsyncGenerator
和typing.AsyncGenerator
的详细信息,请参阅 注解生成器和协程。3.6.1 版本新增。
3.9 版本起已弃用:
collections.abc.AsyncGenerator
现在支持下标操作 ([]
)。参见 PEP 585 和 泛型别名类型。在 3.13 版本中更改:
SendType
形参现在有一个默认值。
- class typing.AsyncIterable(Generic[T_co])¶
已弃用的别名,指向
collections.abc.AsyncIterable
。在 3.5.2 版本中添加。
3.9 版本起已弃用:
collections.abc.AsyncIterable
现在支持下标操作 ([]
)。参见 PEP 585 和 泛型别名类型。
- class typing.AsyncIterator(AsyncIterable[T_co])¶
已弃用的别名,指向
collections.abc.AsyncIterator
。在 3.5.2 版本中添加。
3.9 版本起已弃用:
collections.abc.AsyncIterator
现在支持下标操作 ([]
)。参见 PEP 585 和 泛型别名类型。
- class typing.Awaitable(Generic[T_co])¶
已弃用的别名,指向
collections.abc.Awaitable
。在 3.5.2 版本中添加。
自 3.9 版本起已弃用:
collections.abc.Awaitable
现在支持下标操作 ([]
)。请参阅 PEP 585 和 泛型别名类型。
在 collections.abc
中其他 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
别名。有关在类型注解中使用
collections.abc.Generator
和typing.Generator
的详细信息,请参阅 注解生成器和协程。自 3.9 版本起已弃用:
collections.abc.Generator
现在支持下标操作 ([]
)。请参阅 PEP 585 和 泛型别名类型。在 3.13 版本中变更: 添加了发送和返回类型的默认值。
- class typing.Hashable¶
已弃用的
collections.abc.Hashable
别名。自 3.12 版本起已弃用: 请直接使用
collections.abc.Hashable
。
- class typing.Reversible(Iterable[T_co])¶
已弃用的
collections.abc.Reversible
别名。自 3.9 版本起已弃用:
collections.abc.Reversible
现在支持下标操作 ([]
)。请参阅 PEP 585 和 泛型别名类型。
- class typing.Sized¶
已弃用的
collections.abc.Sized
别名。自 3.12 版本起已弃用: 请直接使用
collections.abc.Sized
。
在 contextlib
中的 ABC 的别名¶
- class typing.ContextManager(Generic[T_co, ExitT_co])¶
已弃用的
contextlib.AbstractContextManager
别名。第一个类型参数
T_co
表示__enter__()
方法返回的类型。可选的第二个类型参数ExitT_co
,默认为bool | None
,表示__exit__()
方法返回的类型。在 3.5.4 版本中新增。
自 3.9 版本起已弃用:
contextlib.AbstractContextManager
现在支持下标操作 ([]
)。请参阅 PEP 585 和 泛型别名类型。3.13 版本更改: 添加了可选的第二个类型参数
ExitT_co
。
- class typing.AsyncContextManager(Generic[T_co, AExitT_co])¶
已弃用,是
contextlib.AbstractAsyncContextManager
的别名。第一个类型参数
T_co
表示__aenter__()
方法返回的类型。可选的第二个类型参数AExitT_co
,默认为bool | None
,表示__aexit__()
方法返回的类型。3.6.2 版本中新增。
3.9 版本起已弃用:
contextlib.AbstractAsyncContextManager
现在支持下标 ([]
)。请参阅 PEP 585 和 泛型别名类型。3.13 版本更改: 添加了可选的第二个类型参数
AExitT_co
。
主要功能的弃用时间线¶
typing
中的某些功能已被弃用,并可能在未来的 Python 版本中删除。下表总结了主要弃用,方便您查阅。这可能会发生变化,并且并非列出所有弃用。
功能 |
弃用版本 |
预计删除时间 |
PEP/issue |
---|---|---|---|
|
3.9 |
未定(更多信息请参阅 已弃用的别名) |
|
3.9 |
3.14 |
||
3.11 |
未定 |
||
3.12 |
未定 |
||
3.12 |
未定 |
||
3.13 |
3.15 |
||
3.13 |
3.18 |