typing
—- 类型提示支持
3.5 新版功能.
源码: Lib/typing.py
注解
Python 运行时不强制执行函数和变量类型注解,但这些注解可用于类型检查器、IDE、静态检查器等第三方工具。
本模块为 PEP 484 、PEP 526 、PEP 544 、PEP 586 、PEP 589 和 PEP 591 中的类型提示提供运行时支持。Any
、Union
、Tuple
、Callable
、TypeVar
和 Generic
等类型是最基础的组件。完整说明详见 PEP 484,类型提示简介请参阅 PEP 483。
下面的函数接收与返回的都是字符串,注解方式如下:
def greeting(name: str) -> str:
return 'Hello ' + name
greeting
函数中,参数 name
的类型是 str
,返回类型也是 str
。子类型也可以当作参数。
类型别名
把类型赋给别名,就可以定义类型别名。本例中,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
NewType()
辅助函数可创建不同的新类型:
from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)
静态类型检查器把新类型当作原始类型的子类,这种方式适用于捕捉逻辑错误:
def get_user_name(user_id: UserId) -> str:
...
# typechecks
user_a = get_user_name(UserId(42351))
# does not typecheck; an int is not a UserId
user_b = get_user_name(-1)
UserId
类型的变量可执行所有 int
操作,但返回结果都是 int
类型。这种方式允许在预期 int
时传入 UserId
,还能防止意外创建无效的 UserId
:
# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)
注意,只有静态类型检查器强制执行这些检查。在运行时,Derived = NewType('Derived', Base)
语句把 Derived
当作函数,该函数直接返回传递给它的任何参数。即,Derived(some_value)
表达式不创建新类,或引入超出调用常规函数的开销。
更确切地说,在运行时,some_value is Derived(some_value)
表达式总为 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
无需指定调用签名,用省略号字面量替换类型提示里的参数列表: 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)
泛型类型支持多个类型变量,不过,类型变量可能会受到限制:
from typing import TypeVar, Generic
...
T = TypeVar('T')
S = TypeVar('S', int, str)
class StrangePair(Generic[T, S]):
...
Generic
类型变量的参数应各不相同。下列代码就是无效的:
from typing import TypeVar, Generic
...
T = TypeVar('T')
class Pair(Generic[T, T]): # INVALID
...
Generic
支持多重继承:
from collections.abc import Sized
from typing import TypeVar, Generic
T = TypeVar('T')
class LinkedList(Sized, Generic[T]):
...
继承自泛型类时,可以修正某些类型变量:
from collections.abc import Mapping
from typing import TypeVar
T = TypeVar('T')
class MyDict(Mapping[str, T]):
...
比如,本例中 MyDict
调用的单参数,T
。
未指定泛型类的类型参数时,每个位置的类型都预设为 Any
。下例中,MyIterable
不是泛型,但却隐式继承了 Iterable[Any]
:
from collections.abc import Iterable
class MyIterable(Iterable): # Same as Iterable[Any]
还支持用户定义的泛型类型别名。例如:
from collections.abc import Iterable
from typing import TypeVar, Union
S = TypeVar('S')
Response = Union[Iterable[S], int]
# Return type here is same as Union[Iterable[str], int]
def response(query: str) -> Response[str]:
...
T = TypeVar('T', int, float, complex)
Vec = Iterable[tuple[T, T]]
def inproduct(v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
return sum(x*y for x, y in v)
在 3.7 版更改: Generic
不再支持自定义元类。
抽象基类可作为用户定义的泛型类的基类,且不会与元类冲突。现已不再支持泛型元类。参数化泛型的输出结果会被缓存,typing 模块的大多数类型都可哈希、可进行等价对比。
Any
类型
Any
是一种特殊的类型。静态类型检查器认为所有类型均与 Any
兼容,同样,Any
也与所有类型兼容。
也就是说,可对 Any
类型的值执行任何操作或方法调用,并赋值给任意变量:
from typing import Any
a = None # type: Any
a = [] # OK
a = 2 # OK
s = '' # type: str
s = a # OK
def foo(item: Any) -> int:
# Typechecks; 'item' could be any type,
# and that type might have a 'bar' method
item.bar()
...
注意,Any
类型的值赋给更精确的类型时,不执行类型检查。例如,把 a
赋给 s
,在运行时,即便 s
已声明为 str
类型,但接收 int
值时,静态类型检查器也不会报错。
此外,未指定返回值与参数类型的函数,都隐式地默认使用 Any
:
def legacy_parser(text):
...
return data
# A static type checker will treat the above
# as having the same signature as:
def legacy_parser(text: Any) -> Any:
...
return data
需要混用动态与静态类型代码时,此操作把 Any
当作 应急出口。
Any
和 object
的区别。与 Any
相似,所有类型都是 object
的子类型。然而,与 Any
不同,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")
使用 object
,说明值能以类型安全的方式转为任何类型。使用 Any
,说明值是动态类型。
名义子类型 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.Any
不受限的特殊类型。
typing.NoReturn
标记没有返回值的函数的特殊类型。例如:
from typing import NoReturn
def stop() -> NoReturn:
raise RuntimeError('no way')
3.5.4 新版功能.
3.6.2 新版功能.
特殊形式
可用于类型注解,且支持 []
,每种形式都有其独特的句法。
typing.Tuple
元组类型; Tuple[X, Y]
是二项元组类型,第一个元素的类型是 X,第二个元素的类型是 Y。空元组的类型可写为 Tuple[()]
。
例:Tuple[T1, T2]
是二项元组,类型变量分别为 T1 和 T2。Tuple[int, float, str]
是由整数、浮点数、字符串组成的三项元组。
可用省略号字面量指定同质变长元组,例如,Tuple[int, ...]
。Tuple
与 Tuple[Any, ...]
等价,也与 tuple
等价。
3.9 版后已移除: builtins.tuple
现已支持 []
。详见 PEP 585 与 Generic Alias Type。
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 与 Generic Alias Type。
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 与 Generic Alias Type。
typing.Literal
表示类型检查器对应变量或函数参数的值等价于给定字面量(或多个字面量之一)的类型。例如:
def validate_simple(data: Any) -> Literal[True]: # always returns True
...
MODE = Literal['r', 'rb', 'w', 'wb']
def open_helper(file: str, mode: MODE) -> str:
...
open_helper('/some/path', 'r') # Passes type check
open_helper('/other/path', 'typo') # Error in type checker
Literal[...]
不能创建子类。在运行时,任意值均可作为 Literal[...]
的类型参数,但类型检查器可以对此加以限制。字面量类型详见 PEP 586 。
3.8 新版功能.
在 3.9.1 版更改: Literal
现在能去除形参的重复。 Literal
对象的相等性比较不再依赖顺序。 现在如果有某个参数不为 hashable,Literal
对象在相等性比较期间将引发 TypeError
。
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
进行静态类型检查(例如,通过 mypy 或 Pyre,可安全地忽略 x
),也可以在特定应用程序中实现 x
的运行时访问。
毕竟,如何解释注解(如有)由处理 Annotated
类型的工具/库负责。工具/库处理 Annotated
类型时,扫描所有注解以确定是否需要进行处理(例如,使用 isinstance()
)。
工具/库不支持注解,或遇到未知注解时,应忽略注解,并把注解类型当作底层类型。
是否允许客户端在一个类型上使用多个注解,以及如何合并这些注解,由处理注解的工具决定。
Annotated
类型支持把多个相同(或不同)的单个(或多个)类型注解置于任意节点。因此,使用这些注解的工具/库要负责处理潜在的重复项。例如,执行值范围分析时,应允许以下操作:
T1 = Annotated[int, ValueRange(-10, 5)]
T2 = Annotated[T1, ValueRange(-20, 3)]
传递 include_extras=True
至 get_type_hints()
,即可在运行时访问额外的注解。
语义详情:
Annotated
的第一个参数必须是有效类型。支持多个类型标注(
Annotated
支持可变参数):Annotated[int, ValueRange(3, 10), ctype("char")]
调用
Annotated
至少要有两个参数(Annotated[int]
是无效的)注解的顺序会被保留,且影响等价检查:
Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[
int, ctype("char"), ValueRange(3, 10)
]
嵌套
Annotated
类型会被展平,元数据从最内层注解依序展开:Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
int, ValueRange(3, 10), ctype("char")
]
不移除注解重复项:
Annotated[int, ValueRange(3, 10)] != Annotated[
int, ValueRange(3, 10), ValueRange(3, 10)
]
Annotated
可用于嵌套或泛型别名:T = TypeVar('T')
Vec = Annotated[list[tuple[T, T]], MaxLen(10)]
V = Vec[int]
V == Annotated[list[tuple[int, int]], MaxLen(10)]
3.9 新版功能.
构建泛型类型
以下内容是创建泛型类型的基石,但不在注解内使用。
class typing.Generic
用于泛型类型的抽象基类。
泛型类型一般通过继承含一个或多个类型变量的类实例进行声明。例如,泛型映射类型定义如下:
class Mapping(Generic[KT, VT]):
def __getitem__(self, key: KT) -> VT:
...
# Etc.
该类的用法如下:
X = TypeVar('X')
Y = TypeVar('Y')
def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y:
try:
return mapping[key]
except KeyError:
return default
class typing.TypeVar
类型变量。
用法:
T = TypeVar('T') # Can be anything
A = TypeVar('A', str, bytes) # Must be str or bytes
类型变量主要是为静态类型检查器提供支持,用于泛型类型与泛型函数定义的参数。有关泛型类型,详见 Generic
。泛型函数的写法如下:
def repeat(x: T, n: int) -> Sequence[T]:
"""Return a list containing n references to x."""
return [x]*n
def longest(x: A, y: A) -> A:
"""Return the longest of two strings."""
return x if len(x) >= len(y) else y
本质上,后例的签名重载了 (str, str) -> str
与 (bytes, bytes) -> bytes
。注意,参数是 str
子类的实例时,返回类型仍是纯 str
。
在运行时,isinstance(x, T)
会触发 TypeError
异常。一般而言,isinstance()
和 issubclass()
不应与类型搭配使用。
通过 covariant=True
或 contravariant=True
可以把类型变量标记为协变量或逆变量。详见 PEP 484。默认情况下,类型变量是不变量。类型变量还可以用 bound=<type>
指定上限。这里的意思是,(显式或隐式地)取代类型变量的实际类型必须是限定类型的子类,详见 PEP 484。
typing.AnyStr
AnyStr
类型变量的定义为 AnyStr = TypeVar('AnyStr', str, bytes)
。
这里指的是,它可以接受任意同类字符串,但不支持混用不同类别的字符串。例如:
def concat(a: AnyStr, b: AnyStr) -> AnyStr:
return a + b
concat(u"foo", u"bar") # Ok, output has type 'unicode'
concat(b"foo", b"bar") # Ok, output has type 'bytes'
concat(u"foo", b"bar") # Error, cannot mix unicode and bytes
class typing.Protocol
(Generic)
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__
这个附加属性,提供了映射字段名与字段类型的字典。(字段名在 _fields
属性内,默认值在 _field_defaults
属性内,这两项都是命名元组 API 的组成部分。)
NamedTuple
子类也支持文档字符串与方法:
class Employee(NamedTuple):
"""Represents an employee."""
name: str
id: int = 3
def __repr__(self) -> str:
return f'<Employee {self.name}, id={self.id}>'
反向兼容用法:
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
在 3.6 版更改: 添加了对 PEP 526 中变量注解句法的支持。
在 3.6.1 版更改: 添加了对默认值、方法、文档字符串的支持。
在 3.8 版更改: _field_types
和 __annotations__
属性现已使用常规字典,不再使用 OrderedDict
实例。
在 3.9 版更改: 移除了 _field_types
属性, 改用具有相同信息,但更标准的 __annotations__
属性。
typing.NewType
(name, tp)
用于为类型检查器标明不同类型的辅助函数,详见 NewType。在运行时,它返回一个返回其参数的函数。用法如下:
UserId = NewType('UserId', int)
first_user = UserId(1)
3.5.2 新版功能.
class typing.TypedDict
(dict)
把类型提示添加至字典的特殊构造器。在运行时,它是纯 dict
。
TypedDict
声明一个字典类型,该类型预期所有实例都具有一组键集,其中,每个键都与对应类型的值关联。运行时不检查此预期,而是由类型检查器强制执行。用法如下:
class Point2D(TypedDict):
x: int
y: int
label: str
a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK
b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check
assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
用于内省的类型信息可通过 Point2D.__annotations__
和 Point2D.__total__
访问。为了让不支持 PEP 526 的老版 Python 也能使用此功能,TypedDict
支持两个附加的等价句法形式:
Point2D = TypedDict('Point2D', x=int, y=int, label=str)
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
默认情况下,所有键都必须列在 TypedDict 里。不过,也可以通过指定 total 参数进行重写。用法如下:
class point2D(TypedDict, total=False):
x: int
y: int
这段代码的意思是,可以省略 point2D 这个 TypedDict 中的任意键。类型检查器只支持字面量 False 或 True 作为 total 参数的值。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 和 Generic Alias Type。
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 与 Generic Alias Type。
class typing.Set
(set, MutableSet[T])
builtins.set
的泛型版本。适用于注解返回类型。注解参数时,最好使用 AbstractSet
等抽象容器类型。
3.9 版后已移除: builtins.set
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.FrozenSet
(frozenset, AbstractSet[T_co])
builtins.frozenset
的泛型版本。
3.9 版后已移除: builtins.frozenset
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
注解
Tuple
是一种特殊形式。
collections
对应类型
class typing.DefaultDict
(collections.defaultdict, MutableMapping[KT, VT])
collections.defaultdict
的泛型版本。
3.5.2 新版功能.
3.9 版后已移除: collections.defaultdict
现已支持 []
。详见 PEP 585 与 Generic Alias Type。
class typing.OrderedDict
(collections.OrderedDict, MutableMapping[KT, VT])
collections.OrderedDict
的泛型版本。
3.7.2 新版功能.
3.9 版后已移除: collections.OrderedDict
现已支持 []
。详见 PEP 585 与 Generic Alias Type。
class typing.ChainMap
(collections.ChainMap, MutableMapping[KT, VT])
collections.ChainMap
的泛型版本。
3.5.4 新版功能.
3.6.1 新版功能.
3.9 版后已移除: collections.ChainMap
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.Counter
(collections.Counter, Dict[T, int])
collections.Counter
的泛型版本。
3.5.4 新版功能.
3.6.1 新版功能.
3.9 版后已移除: collections.Counter
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.Deque
(deque, MutableSequence[T])
collections.deque
的泛型版本。
3.5.4 新版功能.
3.6.1 新版功能.
3.9 版后已移除: collections.deque
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
其他具象类型
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 与 Generic Alias Type。
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 与 Generic Alias Type。
class typing.ByteString
(Sequence[int])
collections.abc.ByteString
的泛型版本。
该类型代表了 bytes
、bytearray
、memoryview
等字节序列类型。
作为该类型的简称,bytes
可用于标注上述任意类型的参数。
3.9 版后已移除: collections.abc.ByteString
现已支持 []
。详见 PEP 585 与 Generic Alias Type。
class typing.Collection
(Sized, Iterable[T_co], Container[T_co])
collections.abc.Collection
的泛型版本。
3.6.0 新版功能.
3.9 版后已移除: collections.abc.Collection
现已支持 []
。详见 PEP 585 与 Generic Alias Type。
class typing.Container
(Generic[T_co])
collections.abc.Container
的泛型版本。
3.9 版后已移除: collections.abc.Container
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.ItemsView
(MappingView, Generic[KT_co, VT_co])
collections.abc.ItemsView
的泛型版本。
3.9 版后已移除: collections.abc.ItemsView
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.KeysView
(MappingView[KT_co], AbstractSet[KT_co])
collections.abc.KeysView
的泛型版本。
3.9 版后已移除: collections.abc.KeysView
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
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 和 Generic Alias Type。
class typing.MappingView
(Sized, Iterable[T_co])
collections.abc.MappingView
的泛型版本。
3.9 版后已移除: collections.abc.MappingView
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.MutableMapping
(Mapping[KT, VT])
collections.abc.MutableMapping
的泛型版本。
3.9 版后已移除: collections.abc.MutableMapping
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.MutableSequence
(Sequence[T])
collections.abc.MutableSequence
的泛型版本。
3.9 版后已移除: collections.abc.MutableSequence
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.MutableSet
(AbstractSet[T])
collections.abc.MutableSet
的泛型版本。
3.9 版后已移除: collections.abc.MutableSet
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.Sequence
(Reversible[T_co], Collection[T_co])
collections.abc.Sequence
的泛型版本。
3.9 版后已移除: collections.abc.Sequence
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.ValuesView
(MappingView[VT_co])
collections.abc.ValuesView
的泛型版本。
3.9 版后已移除: collections.abc.ValuesView
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
collections.abc
对应的其他类型
class typing.Iterable
(Generic[T_co])
collections.abc.Iterable
的泛型版本。
3.9 版后已移除: collections.abc.Iterable
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.Iterator
(Iterable[T_co])
collections.abc.Iterator
的泛型版本。
3.9 版后已移除: collections.abc.Iterator
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
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 和 Generic Alias Type。
class typing.Hashable
class typing.Reversible
(Iterable[T_co])
collections.abc.Reversible
的泛型版本。
3.9 版后已移除: collections.abc.Reversible
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
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 = None # type: Coroutine[list[str], str, int]
...
x = c.send('hi') # type: list[str]
async def bar() -> None:
x = await c # type: int
3.5.3 新版功能.
3.9 版后已移除: collections.abc.Coroutine
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
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 和 Generic Alias Type。
class typing.AsyncIterable
(Generic[T_co])
collections.abc.AsyncIterable
的泛型版本。
3.5.2 新版功能.
3.9 版后已移除: collections.abc.AsyncIterable
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.AsyncIterator
(AsyncIterable[T_co])
collections.abc.AsyncIterator
的泛型版本。
3.5.2 新版功能.
3.9 版后已移除: collections.abc.AsyncIterator
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.Awaitable
(Generic[T_co])
collections.abc.Awaitable
的泛型版本。
3.5.2 新版功能.
3.9 版后已移除: collections.abc.Awaitable
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
上下文管理器类型
class typing.ContextManager
(Generic[T_co])
contextlib.AbstractContextManager
的泛型版本。
3.5.4 新版功能.
3.6.0 新版功能.
3.9 版后已移除: contextlib.AbstractContextManager
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
class typing.AsyncContextManager
(Generic[T_co])
contextlib.AbstractAsyncContextManager
的泛型版本。
3.5.4 新版功能.
3.6.2 新版功能.
3.9 版后已移除: contextlib.AbstractAsyncContextManager
现已支持 []
。详见 PEP 585 和 Generic Alias Type。
协议
这些协议由 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 新版功能.
class typing.ForwardRef
用于字符串前向引用的内部类型表示的类。 例如,List["SomeClass"]
会被隐式转换为 List[ForwardRef("SomeClass")]
。 这个类不应由用户来实例化,但可以由内省工具使用。
注解
PEP 585 泛型类型例如 list["SomeClass"]
将不会被隐式地转换为 list[ForwardRef("SomeClass")]
因而将不会自动解析为 list[SomeClass]
。
3.7.4 新版功能.
常量
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
引用。局部变量的类型注释不会被评估,因此,第二个注解不需要用引号引起来。
注解
Python 3.7 或更高版本中使用 from __future__ import
时,函数定义时不处理注解, 而是把注解当作字符串存在 __annotations__
里,这样就不必为注解使用引号。(详见 PEP 563)。
3.5.2 新版功能.