typing
—— 对类型提示的支持¶
3.5 版新加入.
源代码: Lib/typing.py
備註
Python 运行时不强制要求函数与变量类型注解。它们可被类型检查器、IDE、错误检查器等第三方工具使用。
这个模块提供对类型提示的运行时支持。最基本的支持包括 Any
, Union
, Callable
, TypeVar
, 和 Generic
。关于完整的规范,请参考 PEP 484 。关于类型提示的简化介绍,请参考 PEP 483 。
下面的函数接收与返回的都是字符串,注解方式如下:
def greeting(name: str) -> str:
return 'Hello ' + name
greeting
函数中,参数 name
的类型应是 str
,返回类型是 str
。子类型也可以作为参数。
新的功能频繁地被添加到 typing
模块中。typing_extensions 包提供了这些新功能对旧版本 Python 的向后移植。
相关的 PEP¶
自从在 PEP 484 和 PEP 483 中首次引入类型提示以来,一些 PEP 已经修改和增强了 Python 的类型注释框架。包括:
- PEP 544: Protocol:结构子类型(静态鸭子类型)。
引入
Protocol
和@runtime_checkable
装饰器。
- PEP 585: 标准集合中的类型提示泛型
引入
types.GenericAlias
和使用标准库类作为 通用类型 的能力。
类型别名¶
类型别名是通过为类型赋值为指定的别名来定义的。 在本例中,Vector
和 list[float]
将被视为可互换的同义词:
Vector = list[float]
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
# typechecks; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])
类型别名适用于简化复杂的类型签名。例如:
from collections.abc import Sequence
ConnectionOptions = dict[str, str]
Address = tuple[str, int]
Server = tuple[Address, ConnectionOptions]
def broadcast_message(message: str, servers: Sequence[Server]) -> None:
...
# The static type checker will treat the previous type signature as
# being exactly equivalent to this one.
def broadcast_message(
message: str,
servers: Sequence[tuple[tuple[str, int], dict[str, str]]]) -> None:
...
注意,None
能作为类型提示是一个特例,它会被自动替换为 type(None)
。
NewType¶
Use the NewType()
helper to create distinct types:
from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)
静态类型检查器把新类型当作原始类型的子类,这种方式适用于捕捉逻辑错误:
def get_user_name(user_id: UserId) -> str:
...
# typechecks
user_a = get_user_name(UserId(42351))
# does not typecheck; an int is not a UserId
user_b = get_user_name(-1)
UserId
类型的变量可执行所有 int
操作,但返回结果都是 int
类型。这种方式允许在预期 int
时传入 UserId
,还能防止意外创建无效的 UserId
:
# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)
Note that these checks are enforced only by the static type checker. At runtime,
the statement Derived = NewType('Derived', Base)
will make Derived
a
callable that immediately returns whatever parameter you pass it. That means
the expression Derived(some_value)
does not create a new class or introduce
any overhead beyond that of a regular function call.
更确切地说,在运行时,some_value is Derived(some_value)
表达式总为 True。
也就是说,不能创建 Derived
的子类型,因为,在运行时,它是标识函数,不是真正的类型:
from typing import NewType
UserId = NewType('UserId', int)
# Fails at runtime and does not typecheck
class AdminUserId(UserId): pass
然而,我们可以在 "派生的" NewType
的基础上创建一个 NewType
。
from typing import NewType
UserId = NewType('UserId', int)
ProUserId = NewType('ProUserId', UserId)
同时,ProUserId
的类型检查也可以按预期执行。
详见 PEP 484。
備註
请记住使用类型别名将声明两个类型是相互 等价 的。 使用 Alias = Original
将使静态类型检查器在任何情况下都把 Alias
视为与 Original
完全等价。 这在你想要简化复杂的类型签名时会很有用处。
反之,NewType
声明把一种类型当作另一种类型的 子类型。Derived = NewType('Derived', Original)
时,静态类型检查器把 Derived
当作 Original
的 子类 ,即,Original
类型的值不能用在预期 Derived
类型的位置。这种方式适用于以最小运行时成本防止逻辑错误。
3.5.2 版新加入.
可调对象(Callable)¶
预期特定签名回调函数的框架可以用 Callable[[Arg1Type, Arg2Type], ReturnType]
实现类型提示。
例如:
from collections.abc import Callable
def feeder(get_next_item: Callable[[], str]) -> None:
# Body
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
# Body
async def on_update(value: str) -> None:
# Body
callback: Callable[[str], Awaitable[None]] = on_update
无需指定调用签名,用省略号字面量替换类型提示里的参数列表: Callable[..., ReturnType]
,就可以声明可调对象的返回类型。
泛型(Generic)¶
容器中,对象的类型信息不能以泛型方式静态推断,因此,抽象基类扩展支持下标,用于表示容器元素的预期类型。
from collections.abc import Mapping, Sequence
def notify_by_email(employees: Sequence[Employee],
overrides: Mapping[str, str]) -> None: ...
要参数化泛型,可使用 typing 中的 TypeVar
工厂。
from collections.abc import Sequence
from typing import TypeVar
T = TypeVar('T') # Declare type variable
def first(l: Sequence[T]) -> T: # Generic function
return l[0]
用户定义的泛型类型¶
用户定义的类可以定义为泛型类。
from typing import TypeVar, Generic
from logging import Logger
T = TypeVar('T')
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message)
Generic[T]
是定义类 LoggedVar
的基类,该类使用单类型参数 T
。在该类体内,T
是有效的类型。
Generic
基类定义了 __class_getitem__()
,因此,LoggedVar[t]
也是有效类型:
from collections.abc import Iterable
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
for var in vars:
var.set(0)
一个泛型可以有任何数量的类型变量。所有种类的 TypeVar
都可以作为泛型的参数:
from typing import TypeVar, Generic, Sequence
T = TypeVar('T', contravariant=True)
B = TypeVar('B', bound=Sequence[bytes], covariant=True)
S = TypeVar('S', int, str)
class WeirdTrio(Generic[T, B, S]):
...
Generic
类型变量的参数应各不相同。下列代码就是无效的:
from typing import TypeVar, Generic
...
T = TypeVar('T')
class Pair(Generic[T, T]): # INVALID
...
您可以通过 Generic
来使用多重继承:
from collections.abc import Sized
from typing import TypeVar, Generic
T = TypeVar('T')
class LinkedList(Sized, Generic[T]):
...
继承自泛型类时,可以修正某些类型变量:
from collections.abc import Mapping
from typing import TypeVar
T = TypeVar('T')
class MyDict(Mapping[str, T]):
...
在这个例子中,MyDict
就只有一个参数 T
。
未指定泛型类的类型参数时,每个位置的类型都预设为 Any
。下例中,MyIterable
不是泛型,但却隐式继承了 Iterable[Any]
:
from collections.abc import Iterable
class MyIterable(Iterable): # Same as Iterable[Any]
还支持用户定义的泛型类型别名。例如:
from collections.abc import Iterable
from typing import TypeVar, Union
S = TypeVar('S')
Response = Union[Iterable[S], int]
# Return type here is same as Union[Iterable[str], int]
def response(query: str) -> Response[str]:
...
T = TypeVar('T', int, float, complex)
Vec = Iterable[tuple[T, T]]
def inproduct(v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
return sum(x*y for x, y in v)
3.7 版更變: Generic
不再支持自定义元类。
抽象基类可作为用户定义的泛型类的基类,且不会与元类冲突。现已不再支持泛型元类。参数化泛型的输出结果会被缓存,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:
# Typechecks; 'item' could be any type,
# and that type might have a 'bar' method
item.bar()
...
注意,Any
类型的值赋给更精确的类型时,不执行类型检查。例如,把 a
赋给 s
,在运行时,即便 s
已声明为 str
类型,但接收 int
值时,静态类型检查器也不会报错。
此外,未指定返回值与参数类型的函数,都隐式地默认使用 Any
:
def legacy_parser(text):
...
return data
# A static type checker will treat the above
# as having the same signature as:
def legacy_parser(text: Any) -> Any:
...
return data
需要混用动态与静态类型代码时,此操作把 Any
当作 应急出口。
Any
和 object
的区别。与 Any
相似,所有类型都是 object
的子类型。然而,与 Any
不同,object 不可逆:object
不是 其它类型的子类型。
就是说,值的类型是 object
时,类型检查器几乎会拒绝所有对它的操作,并且,把它赋给更精确的类型变量(或返回值)属于类型错误。例如:
def hash_a(item: object) -> int:
# Fails; an object does not have a 'magic' method.
item.magic()
...
def hash_b(item: Any) -> int:
# Typechecks
item.magic()
...
# Typechecks, since ints and strs are subclasses of object
hash_a(42)
hash_a("foo")
# Typechecks, since Any is compatible with all types
hash_b(42)
hash_b("foo")
名义子类型 vs 结构子类型¶
最初 PEP 484 将 Python 静态类型系统定义为使用 名义子类型。这意味着当且仅当类 A
是 B
的子类时,才满足有类 B
预期时使用类 A
。
此项要求以前也适用于抽象基类,例如,Iterable
。这种方式的问题在于,定义类时必须显式说明,既不 Pythonic,也不是动态类型式 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
,用户可以定义新的自定义协议(见下文中的例子)。
模块内容¶
本模块定义了下列类、函数和修饰器。
備註
本模块定义了一些类型,作为标准库中已有的类的子类,从而可以让 Generic
支持 []
中的类型变量。Python 3.9 中,这些标准库的类已支持 []
,因此,这些类型就变得冗余了。
Python 3.9 弃用了这些冗余类型,但解释器并未提供相应的弃用警告。标记弃用类型的工作留待支持 Python 3.9 及以上版本的类型检查器实现。
Python 3.9.0 发布五年后的首个 Python 发行版将从 typing
模块中移除这些弃用类型。详见 PEP 585 《标准集合的类型提示泛型》。
特殊类型原语¶
特殊类型¶
这些类型可用于类型注解,但不支持 []
。
-
typing.
NoReturn
¶ 标记没有返回值的函数的特殊类型。例如:
from typing import NoReturn def stop() -> NoReturn: raise RuntimeError('no way')
3.5.4 版新加入.
3.6.2 版新加入.
特殊形式¶
可用于类型注解,且支持 []
,每种形式都有其独特的句法。
-
typing.
Tuple
¶ 元组类型;
Tuple[X, Y]
是二项元组类型,第一个元素的类型是 X,第二个元素的类型是 Y。空元组的类型可写为Tuple[()]
。例:
Tuple[T1, T2]
是二项元组,类型变量分别为 T1 和 T2。Tuple[int, float, str]
是由整数、浮点数、字符串组成的三项元组。可用省略号字面量指定同质变长元组,例如,
Tuple[int, ...]
。Tuple
与Tuple[Any, ...]
等价,也与tuple
等价。3.9 版後已棄用:
builtins.tuple
现已支持[]
。详见 PEP 585 与 GenericAlias 类型。
-
typing.
Union
¶ 联合类型;
Union[X, Y]
的意思是,非 X 即 Y。可用
Union[int, str]
等形式定义联合类型。 具体如下:参数必须是某种类型,且至少有一个。
联合类型之联合类型会被展平,例如:
Union[Union[int, str], float] == Union[int, str, float]
单参数之联合类型就是该参数自身,例如:
Union[int] == int # The constructor actually returns int
冗余的参数会被跳过,例如:
Union[int, str, int] == Union[int, str]
比较联合类型,不涉及参数顺序,例如:
Union[int, str] == Union[str, int]
联合类型不能作为子类,也不能实例化。
没有
Union[X][Y]
这种写法。Optional[X]
是Union[X, None]
的缩写。
3.7 版更變: 在运行时,不要移除联合类型中的显式子类。
-
typing.
Optional
¶ 可选类型。
Optional[X]
等价于Union[X, None]
。注意,可选类型与含默认值的可选参数不同。含默认值的可选参数不需要在类型注解上添加
Optional
限定符,因为它仅是可选的。例如:def foo(arg: int = 0) -> None: ...
另一方面,显式应用
None
值时,不管该参数是否可选,Optional
都适用。例如:def foo(arg: Optional[int] = None) -> None: ...
-
typing.
Callable
¶ 可调类型;
Callable[[int], str]
是把(int)转为 str 的函数。下标句法必须与参数列表和返回类型这两个值一起使用。参数列表只能是类型列表或省略号;返回类型只能是单一类型。
没有说明可选参数或关键字参数的句法;这类函数类型很少用作回调类型。
Callable[..., ReturnType]
(省略号字面量)可用于为接受任意数量参数,并返回ReturnType
的可调对象提供类型提示。纯Callable
等价于Callable[..., Any]
,进而等价于collections.abc.Callable
。3.9 版後已棄用:
collections.abc.Callable
现已支持[]
。 详见 PEP 585 与 GenericAlias 类型。
-
class
typing.
Type
(Generic[CT_co])¶ 用
C
注解的变量可以接受类型C
的值。反之,用Type[C]
注解的变量可以接受类自身的值 — 准确地说,是接受C
的 类对象,例如:a = 3 # Has type 'int' b = int # Has type 'Type[int]' c = type(a) # Also has type 'Type[int]'
注意,
Type[C]
为协变量:class User: ... class BasicUser(User): ... class ProUser(User): ... class TeamUser(User): ... # Accepts User, BasicUser, ProUser, TeamUser, ... def make_new_user(user_class: Type[User]) -> User: # ... return user_class()
Type[C]
为协变量的意思是指,C
的所有子类都应使用与C
相同的构造器签名及类方法签名。类型检查器应标记违反此项规定的内容,但也应允许符合指定基类构造器调用的子类进行构造器调用。PEP 484 修订版将来可能会调整类型检查器对这种特例的处理方式。Type
合法的参数仅有类、Any
、类型变量 以及上述类型的联合类型。例如:def new_non_team_user(user_class: Type[Union[BasicUser, ProUser]]): ...
Type[Any]
等价于Type
,进而等价于 Python 元类架构的根基,type
。3.5.2 版新加入.
3.9 版後已棄用:
builtins.type
现已支持[]
。详见 PEP 585 与 GenericAlias 类型。
-
typing.
Literal
¶ 表示类型检查器对应变量或函数参数的值等价于给定字面量(或多个字面量之一)的类型。例如:
def validate_simple(data: Any) -> Literal[True]: # always returns True ... MODE = Literal['r', 'rb', 'w', 'wb'] def open_helper(file: str, mode: MODE) -> str: ... open_helper('/some/path', 'r') # Passes type check open_helper('/other/path', 'typo') # Error in type checker
Literal[...]
不能创建子类。在运行时,任意值均可作为Literal[...]
的类型参数,但类型检查器可以对此加以限制。字面量类型详见 PEP 586 。3.8 版新加入.
-
typing.
ClassVar
¶ 特殊类型注解构造,用于标注类变量。
如 PEP 526 所述,打包在 ClassVar 内的变量注解是指,给定属性应当用作类变量,而不应设置在类实例上。用法如下:
class Starship: stats: ClassVar[dict[str, int]] = {} # class variable damage: int = 10 # instance variable
ClassVar
仅接受类型,也不能使用下标。ClassVar
本身不是类,不应用于isinstance()
或issubclass()
。ClassVar
不改变 Python 运行时行为,但可以用于第三方类型检查器。例如,类型检查器会认为以下代码有错:enterprise_d = Starship(3000) enterprise_d.stats = {} # Error, setting class variable on instance Starship.stats = {} # This is OK
3.5.3 版新加入.
-
typing.
Final
¶ 告知类型检查器某名称不能再次赋值或在子类中重写的特殊类型构造器。例如:
MAX_SIZE: Final = 9000 MAX_SIZE += 1 # Error reported by type checker class Connection: TIMEOUT: Final[int] = 10 class FastConnector(Connection): TIMEOUT = 1 # Error reported by type checker
这些属性没有运行时检查。详见 PEP 591。
3.8 版新加入.
-
typing.
Annotated
¶ PEP 593 (
灵活函数和变量注解
)里引入的类型,可以用上下文特定元数据(Annotated
的参数可变,也可能用它的多个组成部分)装饰现有的类型。具体来说,就是类型提示Annotated[T, x]
用元数据x
注解类型T
。静态分析或运行时都能使用该元数据。库(或工具)处理类型提示Annotated[T, x]
时,在元数据x
不涉及特殊逻辑的情况下,可忽略该类型提示,仅把它当作类型T
。与typing
模块中现有的no_type_check
功能不同,该功能完全禁用了函数或类的类型检查注解,而Annotated
类型则允许对T
进行静态类型检查(可安全地忽略x
),也可以在特定应用程序中实现x
的运行时访问。毕竟,如何解释注解(如有)由处理
Annotated
类型的工具/库负责。工具/库处理Annotated
类型时,扫描所有注解以确定是否需要进行处理(例如,使用isinstance()
)。工具/库不支持注解,或遇到未知注解时,应忽略注解,并把注解类型当作底层类型。
是否允许客户端在一个类型上使用多个注解,以及如何合并这些注解,由处理注解的工具决定。
Annotated
类型支持把多个相同(或不同)的单个(或多个)类型注解置于任意节点。因此,使用这些注解的工具/库要负责处理潜在的重复项。例如,执行值范围分析时,应允许以下操作:T1 = Annotated[int, ValueRange(-10, 5)] T2 = Annotated[T1, ValueRange(-20, 3)]
传递
include_extras=True
至get_type_hints()
,即可在运行时访问额外的注解。语义详情:
Annotated
的第一个参数必须是有效的类型。支持多个类型标注(
Annotated
支持可变参数):Annotated[int, ValueRange(3, 10), ctype("char")]
调用
Annotated
至少要有两个参数(Annotated[int]
是无效的)注解的顺序会被保留,且影响等价检查:
Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[ int, ctype("char"), ValueRange(3, 10) ]
嵌套
Annotated
类型会被展平,元数据从最内层注解依序展开:Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[ int, ValueRange(3, 10), ctype("char") ]
不移除注解重复项:
Annotated[int, ValueRange(3, 10)] != Annotated[ int, ValueRange(3, 10), ValueRange(3, 10) ]
Annotated
可用于嵌套或泛型别名:T = TypeVar('T') Vec = Annotated[list[tuple[T, T]], MaxLen(10)] V = Vec[int] V == Annotated[list[tuple[int, int]], MaxLen(10)]
3.9 版新加入.
构建泛型类型¶
以下内容是创建泛型类型的基石,但不在注解内使用。
-
class
typing.
Generic
¶ 用于泛型类型的抽象基类。
泛型类型一般通过继承含一个或多个类型变量的类实例进行声明。例如,泛型映射类型定义如下:
class Mapping(Generic[KT, VT]): def __getitem__(self, key: KT) -> VT: ... # Etc.
该类的用法如下:
X = TypeVar('X') Y = TypeVar('Y') def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y: try: return mapping[key] except KeyError: return default
-
class
typing.
TypeVar
¶ 类型变量。
用法:
T = TypeVar('T') # Can be anything 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(x: T, n: int) -> Sequence[T]: """Return a list containing n references to x.""" return [x]*n def print_capitalized(x: S) -> S: """Print x capitalized, and return x.""" print(x.capitalize()) return x def concatenate(x: A, y: A) -> A: """Add two strings or bytes objects together.""" return x + y
请注意,类型变量可以是 被绑定的 , 被约束的 ,或者两者都不是,但不能既是被绑定的 又是 被约束的。
约束类型变量和绑定类型变量在几个重要方面具有不同的语义。使用 约束 类型变量意味着它只能被解析为正好是所给的约束之一:
a = concatenate('one', 'two') # Ok, variable 'a' has type 'str' b = concatenate(StringSubclass('one'), StringSubclass('two')) # Inferred type of variable 'b' 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
然而,使用一个 绑定 类型变量,意味着将使用最具体的类型来解析
TypeVar
print_capitalized('a string') # Ok, output has type 'str' class StringSubclass(str): pass print_capitalized(StringSubclass('another string')) # Ok, output has type 'StringSubclass' print_capitalized(45) # error: int is not a subtype of str
类型变量可以被绑定到具体类型、抽象类型( ABC 或 protocol ),甚至是类型的联合:
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
绑定类型变量对于注释作为替代构造函数的
classmethods
特别有用。在下面的例子中( © Raymond Hettinger ),类型变量C
通过使用前向引用被绑定到类Circle
。使用这个类型变量来注解类方法with_circumference
,而不是将返回类型硬编码为Circle
,这意味着类型检查器可以正确推断出返回类型,即使该方法是在一个子类上调用的:import math C = TypeVar('C', bound='Circle') class Circle: """An abstract circle""" def __init__(self, radius: float) -> None: self.radius = radius # Use a type variable to show that the return type # will always be an instance of whatever ``cls`` is @classmethod def with_circumference(cls: type[C], circumference: float) -> C: """Create a circle with the specified circumference""" radius = circumference / (math.pi * 2) return cls(radius) class Tire(Circle): """A specialised circle (made out of rubber)""" MATERIAL = 'rubber' c = Circle.with_circumference(3) # Ok, variable 'c' has type 'Circle' t = Tire.with_circumference(4) # Ok, variable 't' has type 'Tire' (not 'Circle')
在运行时,
isinstance(x, T)
会触发TypeError
异常。一般而言,isinstance()
和issubclass()
不应与类型搭配使用。类型变量可以通过传递
covariant=True
或contravariant=True
来标记协变或逆变。 更多细节请参见 PEP 484 。 默认情况下,类型变量是不变的。
-
typing.
AnyStr
¶ AnyStr
定义为AnyStr = TypeVar('AnyStr', str, bytes)
的约束类型变量
。这里指的是,它可以接受任意同类字符串,但不支持混用不同类别的字符串。例如:
def concat(a: AnyStr, b: AnyStr) -> AnyStr: return a + b concat(u"foo", u"bar") # Ok, output has type 'unicode' concat(b"foo", b"bar") # Ok, output has type 'bytes' concat(u"foo", b"bar") # Error, cannot mix unicode and bytes
-
class
typing.
Protocol
(Generic)¶ Protocol 类的基类。Protocol 类的定义如下:
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。Protocol 类用
runtime_checkable()
(见下文)装饰,忽略类型签名,仅检查给定属性是否存在,充当简要的运行时协议。Protocol 类可以是泛型,例如:
class GenProto(Protocol[T]): def meth(self) -> T: ...
3.8 版新加入.
-
@
typing.
runtime_checkable
¶ 用于把 Protocol 类标记为运行时协议。
该协议可以与
isinstance()
和issubclass()
一起使用。应用于非协议的类时,会触发TypeError
。该指令支持简易结构检查,与collections.abc
的Iterable
非常类似,只擅长做一件事。 例如:@runtime_checkable class Closable(Protocol): def close(self): ... assert isinstance(open('/some/file'), Closable)
備註
runtime_checkable()
只检查所需方法是否存在,但却不检查类型签名! 例如,builtins.complex
支持__float__()
,因此,它能通过SupportsFloat
的issubclass()
检查。 然而,complex.__float__
方法其实只是为了触发含更多信息的TypeError
。3.8 版新加入.
其他特殊指令¶
这些特殊指令是声明类型的基石,但不在注解内使用。
-
class
typing.
NamedTuple
¶ collections.namedtuple()
的类型版本。用法:
class Employee(NamedTuple): name: str id: int
这相当于:
Employee = collections.namedtuple('Employee', ['name', 'id'])
为字段提供默认值,要在类体内赋值:
class Employee(NamedTuple): name: str id: int = 3 employee = Employee('Guido') assert employee.id == 3
带默认值的字段必须在不带默认值的字段后面。
由此产生的类有一个额外的属性
__annotations__
,给出一个 dict ,将字段名映射到字段类型。(字段名在_fields
属性中,默认值在_field_defaults
属性中,这两者都是namedtuple()
API 的一部分。)NamedTuple
子类也支持文档字符串与方法:class Employee(NamedTuple): """Represents an employee.""" name: str id: int = 3 def __repr__(self) -> str: return f'<Employee {self.name}, id={self.id}>'
反向兼容用法:
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
3.6 版更變: 添加了对 PEP 526 中变量注解句法的支持。
3.6.1 版更變: 添加了对默认值、方法、文档字符串的支持。
3.8 版更變:
_field_types
和__annotations__
属性现已使用常规字典,不再使用OrderedDict
实例。3.9 版更變: 移除了
_field_types
属性, 改用具有相同信息,但更标准的__annotations__
属性。
-
typing.
NewType
(name, tp)¶ 用于为类型检查器标明不同类型的辅助函数,详见 NewType。在运行时,它返回一个返回其参数的函数。用法如下:
UserId = NewType('UserId', int) first_user = UserId(1)
3.5.2 版新加入.
-
class
typing.
TypedDict
(dict)¶ 把类型提示添加至字典的特殊构造器。在运行时,它是纯
dict
。TypedDict
声明一个字典类型,该类型预期所有实例都具有一组键集,其中,每个键都与对应类型的值关联。运行时不检查此预期,而是由类型检查器强制执行。用法如下:class Point2D(TypedDict): x: int y: int label: str a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
为了在不支持 PEP 526 的旧版 Python 中使用此特性,
TypedDict
支持两种额外的等价语法形式:使用字面量
dict
作为第二个参数:Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
使用关键字参数:
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
中。 可以通过指定总数来重写这一点。用法: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
是默认的,它使类主体中定义的所有项目都是必需的。一个
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 T = TypeVar('T') class XT(X, Generic[T]): pass # raises TypeError
A
TypedDict
can be introspected via__annotations__
,__total__
,__required_keys__
, and__optional_keys__
.-
__total__
¶ Point2D.__total__
gives the value of thetotal
argument. Example:>>> 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
-
__required_keys__
¶
-
__optional_keys__
¶ Point2D.__required_keys__
和Point2D.__optional_keys__
分别返回frozenset
对象,其中包含必需和非必需键。目前,在同一个 中声明必需和非必需键的唯一方法是混合继承,用一个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
更多示例与
TypedDict
的详细规则,详见 PEP 589。3.8 版新加入.
泛型具象容器¶
对应的内置类型¶
-
class
typing.
Dict
(dict, MutableMapping[KT, VT])¶ dict
的泛型版本。适用于注解返回类型。注解参数时,最好使用Mapping
等抽象容器类型。该类型用法如下:
def count_words(text: str) -> Dict[str, int]: ...
3.9 版後已棄用:
builtins.dict
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
List
(list, MutableSequence[T])¶ list
的泛型版本。适用于注解返回类型。注解参数时,最好使用Sequence
或Iterable
等抽象容器类型。该类型用法如下:
T = TypeVar('T', int, float) def vec2(x: T, y: T) -> List[T]: return [x, y] def keep_positives(vector: Sequence[T]) -> List[T]: return [item for item in vector if item > 0]
3.9 版後已棄用:
builtins.list
现已支持[]
。详见 PEP 585 与 GenericAlias 类型。
-
class
typing.
Set
(set, MutableSet[T])¶ builtins.set
的泛型版本。适用于注解返回类型。注解参数时,最好使用AbstractSet
等抽象容器类型。3.9 版後已棄用:
builtins.set
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
FrozenSet
(frozenset, AbstractSet[T_co])¶ builtins.frozenset
的泛型版本。3.9 版後已棄用:
builtins.frozenset
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
備註
Tuple
是一种特殊形式。
collections
对应类型¶
-
class
typing.
DefaultDict
(collections.defaultdict, MutableMapping[KT, VT])¶ collections.defaultdict
的泛型版本。3.5.2 版新加入.
3.9 版後已棄用:
collections.defaultdict
现已支持[]
。详见 PEP 585 与 GenericAlias 类型。
-
class
typing.
OrderedDict
(collections.OrderedDict, MutableMapping[KT, VT])¶ collections.OrderedDict
的泛型版本。3.7.2 版新加入.
3.9 版後已棄用:
collections.OrderedDict
现已支持[]
。详见 PEP 585 与 GenericAlias 类型。
-
class
typing.
ChainMap
(collections.ChainMap, MutableMapping[KT, VT])¶ collections.ChainMap
的泛型版本。3.5.4 版新加入.
3.6.1 版新加入.
3.9 版後已棄用:
collections.ChainMap
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
Counter
(collections.Counter, Dict[T, int])¶ collections.Counter
的泛型版本。3.5.4 版新加入.
3.6.1 版新加入.
3.9 版後已棄用:
collections.Counter
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
Deque
(deque, MutableSequence[T])¶ collections.deque
的泛型版本。3.5.4 版新加入.
3.6.1 版新加入.
3.9 版後已棄用:
collections.deque
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
其他具象类型¶
-
class
typing.
IO
¶ -
class
typing.
TextIO
¶ -
class
typing.
BinaryIO
¶ 泛型
IO[AnyStr]
及其子类TextIO(IO[str])
、BinaryIO(IO[bytes])
表示 I/O 流——例如open()
返回的对象——的类型。Deprecated since version 3.8, will be removed in version 3.12: 这些类型也在
typing.io
命名空间中,它从未得到类型检查器的支持并将被移除。
-
class
typing.
Pattern
¶ -
class
typing.
Match
¶ 这些类型对应的是从
re.compile()
和re.match()
返回的类型。 这些类型(及相应的函数)是AnyStr
中的泛型并可通过编写Pattern[str]
,Pattern[bytes]
,Match[str]
或Match[bytes]
来具体指定。Deprecated since version 3.8, will be removed in version 3.12: 这些类型也在
typing.re
命名空间中,它从未得到类型检查器的支持并将被移除。3.9 版後已棄用:
re
模块中的Pattern
与Match
类现已支持[]
。详见 PEP 585 与 GenericAlias 类型。
-
class
typing.
Text
¶ Text
是str
的别名。提供了对 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 版新加入.
抽象基类¶
collections.abc
对应的容器¶
-
class
typing.
AbstractSet
(Sized, Collection[T_co])¶ collections.abc.Set
的泛型版本。3.9 版後已棄用:
collections.abc.Set
现已支持[]
。详见 PEP 585 与 GenericAlias 类型。
-
class
typing.
ByteString
(Sequence[int])¶ collections.abc.ByteString
的泛型版本。该类型代表了
bytes
、bytearray
、memoryview
等字节序列类型。作为该类型的简称,
bytes
可用于标注上述任意类型的参数。3.9 版後已棄用:
collections.abc.ByteString
现已支持[]
。详见 PEP 585 与 GenericAlias 类型。
-
class
typing.
Collection
(Sized, Iterable[T_co], Container[T_co])¶ collections.abc.Collection
的泛型版本。3.6.0 版新加入.
3.9 版後已棄用:
collections.abc.Collection
现已支持[]
。详见 PEP 585 与 GenericAlias 类型。
-
class
typing.
Container
(Generic[T_co])¶ collections.abc.Container
的泛型版本。3.9 版後已棄用:
collections.abc.Container
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
ItemsView
(MappingView, Generic[KT_co, VT_co])¶ collections.abc.ItemsView
的泛型版本。3.9 版後已棄用:
collections.abc.ItemsView
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
KeysView
(MappingView[KT_co], AbstractSet[KT_co])¶ collections.abc.KeysView
的泛型版本。3.9 版後已棄用:
collections.abc.KeysView
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
Mapping
(Sized, Collection[KT], Generic[VT_co])¶ collections.abc.Mapping
的泛型版本。用法如下:def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: return word_list[word]
3.9 版後已棄用:
collections.abc.Mapping
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
MappingView
(Sized, Iterable[T_co])¶ collections.abc.MappingView
的泛型版本。3.9 版後已棄用:
collections.abc.MappingView
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
MutableMapping
(Mapping[KT, VT])¶ collections.abc.MutableMapping
的泛型版本。3.9 版後已棄用:
collections.abc.MutableMapping
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
MutableSequence
(Sequence[T])¶ collections.abc.MutableSequence
的泛型版本。3.9 版後已棄用:
collections.abc.MutableSequence
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
MutableSet
(AbstractSet[T])¶ collections.abc.MutableSet
的泛型版本。3.9 版後已棄用:
collections.abc.MutableSet
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
Sequence
(Reversible[T_co], Collection[T_co])¶ collections.abc.Sequence
的泛型版本。3.9 版後已棄用:
collections.abc.Sequence
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
ValuesView
(MappingView[VT_co])¶ collections.abc.ValuesView
的泛型版本。3.9 版後已棄用:
collections.abc.ValuesView
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
collections.abc
对应的其他类型¶
-
class
typing.
Iterable
(Generic[T_co])¶ collections.abc.Iterable
的泛型版本。3.9 版後已棄用:
collections.abc.Iterable
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
Iterator
(Iterable[T_co])¶ collections.abc.Iterator
的泛型版本。3.9 版後已棄用:
collections.abc.Iterator
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
Generator
(Iterator[T_co], Generic[T_co, T_contra, V_co])¶ 生成器可以由泛型类型
Generator[YieldType, SendType, ReturnType]
注解。例如:def echo_round() -> Generator[int, float, str]: sent = yield 0 while sent >= 0: sent = yield round(sent) return 'Done'
注意,与 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 和 GenericAlias 类型。
-
class
typing.
Hashable
¶
-
class
typing.
Reversible
(Iterable[T_co])¶ collections.abc.Reversible
的泛型版本。3.9 版後已棄用:
collections.abc.Reversible
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
Sized
¶
异步编程¶
-
class
typing.
Coroutine
(Awaitable[V_co], Generic[T_co, T_contra, V_co])¶ 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 和 GenericAlias 类型。
-
class
typing.
AsyncGenerator
(AsyncIterator[T_co], Generic[T_co, T_contra])¶ 异步生成器可由泛型类型
AsyncGenerator[YieldType, SendType]
注解。例如:async def echo_round() -> AsyncGenerator[int, float]: sent = yield 0 while sent >= 0.0: rounded = await round(sent) sent = yield rounded
与常规生成器不同,异步生成器不能返回值,因此没有
ReturnType
类型参数。 与Generator
类似,SendType
也属于逆变行为。如果生成器只产生值,可将
SendType
设置为None
:async def infinite_stream(start: int) -> AsyncGenerator[int, None]: while True: yield start start = await increment(start)
此外,可用
AsyncIterable[YieldType]
或AsyncIterator[YieldType]
注解生成器的返回类型:async def infinite_stream(start: int) -> AsyncIterator[int]: while True: yield start start = await increment(start)
3.6.1 版新加入.
3.9 版後已棄用:
collections.abc.AsyncGenerator
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
AsyncIterable
(Generic[T_co])¶ collections.abc.AsyncIterable
的泛型版本。3.5.2 版新加入.
3.9 版後已棄用:
collections.abc.AsyncIterable
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
AsyncIterator
(AsyncIterable[T_co])¶ collections.abc.AsyncIterator
的泛型版本。3.5.2 版新加入.
3.9 版後已棄用:
collections.abc.AsyncIterator
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
Awaitable
(Generic[T_co])¶ collections.abc.Awaitable
的泛型版本。3.5.2 版新加入.
3.9 版後已棄用:
collections.abc.Awaitable
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
上下文管理器类型¶
-
class
typing.
ContextManager
(Generic[T_co])¶ contextlib.AbstractContextManager
的泛型版本。3.5.4 版新加入.
3.6.0 版新加入.
3.9 版後已棄用:
contextlib.AbstractContextManager
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
-
class
typing.
AsyncContextManager
(Generic[T_co])¶ contextlib.AbstractAsyncContextManager
的泛型版本。3.5.4 版新加入.
3.6.2 版新加入.
3.9 版後已棄用:
contextlib.AbstractAsyncContextManager
现已支持[]
。详见 PEP 585 和 GenericAlias 类型。
协议¶
这些协议由 runtime_checkable()
装饰。
-
class
typing.
SupportsAbs
¶ 一个抽象基类,含一个抽象方法
__abs__
,该方法与其返回类型协变。
-
class
typing.
SupportsBytes
¶ 一个抽象基类,含一个抽象方法
__bytes__
。
-
class
typing.
SupportsComplex
¶ 一个抽象基类,含一个抽象方法
__complex__
。
-
class
typing.
SupportsFloat
¶ 一个抽象基类,含一个抽象方法
__float__
。
-
class
typing.
SupportsIndex
¶ 一个抽象基类,含一个抽象方法
__index__
。3.8 版新加入.
-
class
typing.
SupportsInt
¶ 一个抽象基类,含一个抽象方法
__int__
。
-
class
typing.
SupportsRound
¶ 一个抽象基类,含一个抽象方法
__round__
,该方法与其返回类型协变。
函数与装饰器¶
-
typing.
cast
(typ, val)¶ 把一个值转换为指定的类型。
这会把值原样返回。对类型检查器而言这代表了返回值具有指定的类型,在运行时我们故意没有设计任何检查(我们希望让这尽量快)。
-
@
typing.
overload
¶ @overload
装饰器可以修饰支持多个不同参数类型组合的函数或方法。@overload
- 装饰定义的系列必须紧跟一个非@overload
-装饰定义(用于同一个函数/方法)。@overload
-装饰定义仅是为了协助类型检查器, 因为该装饰器会被非@overload
-装饰定义覆盖,后者用于运行时,而且会被类型检查器忽略。在运行时直接调用@overload
装饰的函数会触发NotImplementedError
。下面的重载示例给出了比联合类型或类型变量更精准的类型:@overload def process(response: None) -> None: ... @overload def process(response: int) -> tuple[int, str]: ... @overload def process(response: bytes) -> str: ... def process(response): <actual implementation>
详见 PEP 484,与其他类型语义进行对比。
-
@
typing.
final
¶ 告知类型检查器被装饰的方法不能被覆盖,且被装饰的类不能作为子类的装饰器,例如:
class Base: @final def done(self) -> None: ... class Sub(Base): def done(self) -> None: # Error reported by type checker ... @final class Leaf: ... class Other(Leaf): # Error reported by type checker ...
这些属性没有运行时检查。详见 PEP 591。
3.8 版新加入.
-
@
typing.
no_type_check
¶ 标明注解不是类型提示的装饰器。
用作类或函数的 decorator。用于类时,递归地应用于该类中定义的所有方法,(但不影响超类或子类中定义的方法)。
本方法可直接修改函数。
-
@
typing.
no_type_check_decorator
¶ 让其他装饰器具有
no_type_check()
效果的装饰器。本装饰器用
no_type_check()
里的装饰函数打包其他装饰器。
-
@
typing.
type_check_only
¶ 标记类或函数内不可用于运行时的装饰器。
在运行时,该装饰器本身不可用。实现返回的是私有类实例时,它主要是用于标记在类型存根文件中定义的类。
@type_check_only class Response: # private or not available at runtime code: int def get_header(self, name: str) -> str: ... def fetch_response() -> Response: ...
注意,建议不要返回私有类实例,最好将之设为公共类。
内省辅助器¶
-
typing.
get_type_hints
(obj, globalns=None, localns=None, include_extras=False)¶ 返回函数、方法、模块、类对象的类型提示的字典。
一般情况下,与
obj.__annotations__
相同。此外,可通过在globals
与locals
命名空间里进行评估,以此来处理编码为字符串字面量的前向引用。如有需要,在默认值设置为None
时,可为函数或方法注解添加Optional[t]
。对于类C
,则返回由所有__annotations__
与C.__mro__
逆序合并而成的字典。本函数以递归地方式用
T
替换所有Annotated[T, ...]
, 除非将include_extras
的值设置为True
(详见Annotated
)。例如:class Student(NamedTuple): name: Annotated[str, 'some marker'] get_type_hints(Student) == {'name': str} get_type_hints(Student, include_extras=False) == {'name': str} get_type_hints(Student, include_extras=True) == { 'name': Annotated[str, 'some marker'] }
3.9 版更變: PEP 593 的组成部分,添加了
include_extras
参数。
-
typing.
get_args
(tp)¶
-
typing.
get_origin
(tp)¶ 为泛型类型与特殊类型形式提供了基本的内省功能。
对于
X[Y, Z, ...]
形式的类型对象,这些函数返回X
与(Y, Z, ...)
。如果X
是内置对象或collections
class 的泛型别名, 会将其标准化为原始类。如果X
是包含在其他泛型类型中的Union
或Literal
,(Y, Z, ...)
的顺序会因类型缓存,而与原始参数[Y, Z, ...]
的顺序不同。对于不支持的对象会相应地返回None
或()
。例如:assert get_origin(Dict[str, int]) is dict assert get_args(Dict[int, str]) == (int, str) assert get_origin(Union[int, str]) is Union assert get_args(Union[int, str]) == (int, str)
3.8 版新加入.
常量¶
-
typing.
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 版新加入.