Typing
类型注释让python 有了更好的编辑器提示功能。
基础使用
对函数参数和返回值,进行类型注释
def surface_area_of_cube(edge_length: float) -> str:
return f"The surface area of the cube is {6 * edge_length ** 2}."
类型别名
类型别名适用于简化复杂的类型签名
type Vector = list[float]
# 为了向下兼容,也可以使用以下方式
# Vector = list[float]
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
# 通过类型检查;浮点数列表是合格的 Vector。
new_vector = scale(2.0, [1.0, -4.2, 5.4])
NewType
静态类型检查器把新类型当作原始类型的子类,这种方式适用于捕捉逻辑错误。
不允许继承NewType的产生的类型
from typing import NewType
UserId = NewType('UserId', int)
def get_user_name(user_id: UserId) -> str:
pass
# 通过类型检查
user_a = get_user_name(UserId(42351))
# 'output' 的类型为 'int' 而非 'UserId'
output = UserId(23413) + UserId(54341)
Callable
Callable[[int], str]
使用两个值:参数列表和返回类型
# 接受两个Callable的参数
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
... # 函数体
# ...表示接受任意形参列表
x: Callable[..., str]
x = str # 可以
x = concat # 同样可以
泛型
表示容器元素的预期类型
from collections.abc import Mapping, Sequence
class Employee: ...
# Sequence[Employee] 表明该序列中的所有元素
# 都必须是 "Employee" 的实例。
# Mapping[str, str] 表明该映射中的所有键和所有值
# 都必须是字符串。
def notify_by_email(employees: Sequence[Employee],
overrides: Mapping[str, str]) -> None: ...
类型行参化:
from collections.abc import Sequence
def first[T](l: Sequence[T]) -> T: # 函数是 TypeVar "T" 泛型
return l[0]
TypeVar
from collections.abc import Sequence
from typing import TypeVar
U = TypeVar('U') # 声明类型变量 "U"
def second(l: Sequence[U]) -> U: # 函数是 TypeVar "U" 泛型
return l[1]
Sequence与List的区别:Sequence是一个抽象基类,许多具体的类型(如
list
、tuple
、str
等)都属于Sequence
。Mapping与dict的区别:Mapping表示函数可以接受任何支持键值对访问的类型,如 collections.defaultdict 或自定义的映射类型
标注元组
元组的标注与其他的类型不同。
# 第 1 个元素是个整数,第 2 个元素是个字符串
y: tuple[int, str] = (5, "foo")
# 错误: 类型标注表明是长度为 1 的元组,
# 但 ``z`` 却被赋值为长度为 3 的元组
z: tuple[int] = (1, 2, 3)
# 所有元素都是相同类型的 T,需要使用 tuple[T, ...]
x: tuple[int, ...] = (1, 2)
# ``y`` 只能被赋值为一个空元组
y: tuple[()] = ()
类对象的类型
可以通过对象获取其对应的类型:type(c)
type
的合法形参包括:类, Any
, 类型变量 以及前面这些类型的并集。
type[Any]
等价于 type
,它是 Python 的 元类层级结构 的根对象。
a = 3 # 为 ``int`` 类型
b = int # 为 ``type[int]`` 类型
c = type(a) # 同样为 ``type[int]`` 类型
class User: ...
class ProUser(User): ...
class TeamUser(User): ...
def make_new_user(user_class: type[User]) -> User:
# ...
return user_class()
make_new_user(User) # 可以
make_new_user(ProUser) # 同样可以: ``type[ProUser]`` 是 ``type[User]`` 的子类型
make_new_user(TeamUser) # 仍然可以
make_new_user(User()) # 错误: 预期为 ``type[User]`` 但得到 ``User``
def new_non_team_user(user_class: type[BasicUser | ProUser]): ...
new_non_team_user(BasicUser) # 可以
new_non_team_user(ProUser) # 可以
标注生成器和协程
生成器使用:Generator[YieldType, SendType, ReturnType]
异步生成器使用:AsyncGenerator[YieldType, SendType],不支持ReturnType
当SendType, ReturnType不设置时,默认为None
def echo_round() -> Generator[int, float, str]:
sent = yield 0
while sent >= 0:
sent = yield round(sent)
return 'Done'
# 异步
async def infinite_stream(start: int) -> AsyncGenerator[int]:
while True:
yield start
start = await increment(start)
一些简单的迭代器,可以使用Iterable[YieldType]
或 Iterator[YieldType]
异步:AsyncIterable[YieldType] 和 AsyncIterator[YieldType]
def infinite_stream(start: int) -> Iterator[int]:
while True:
yield start
start += 1
# 异步
async def infinite_stream(start: int) -> AsyncIterator[int]:
while True:
yield start
start = await increment(start)
协程:
from collections.abc import Coroutine
c: Coroutine[list[str], str, int] # 在其他地方定义的协程
x = c.send('hi') # 推断 'x' 的类型为 list[str]
async def bar() -> None:
y = await c # 推断 'y' 的类型为 int
用户定义的泛型类型
围绕单个 类型变量 T 实现参数化的。 这也使得 T 成为类体内部有效的类型。
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
# 为了与 python3.11 兼容,也可以使用Generic
from typing import TypeVar, Generic
T = TypeVar('T')
class LoggedVar(Generic[T]):
typing.Union
Union[X, Y] 等价于 X | Y ,意味着满足 X 或 Y 之一。
Optional[X] 等价于 X | None (或 Union[X, None] ) 。
联合类型之联合类型会被展平,例如:
Union[Union[int, str], float] == Union[int, str, float]
单参数之联合类型就是该参数自身,例如:
Union[int] == int # 该构造器确实返回 int
冗余的参数会被跳过,例如:
Union[int, str, int] == Union[int, str] == int | str
比较联合类型,不涉及参数顺序,例如:
Union[int, str] == Union[str, int]
不可创建
Union
的子类或实例。没有
Union[X][Y]
这种写法。