
本文深入探讨了在python中处理嵌套 `typing.annotated` 类型时,如何优雅地提取其原始“裸”类型签名的挑战。通过介绍一种基于类型树递归遍历的解决方案,我们展示了如何利用 `typing` 模块的 `get_origin` 和 `get_args` 函数,构建一个通用且健壮的工具,以准确地从复杂类型结构中移除所有 `annotated` 注解,还原其纯粹的类型表示,而无需依赖复杂的正则表达式。
typing.Annotated 是 Python 3.9 引入的一个强大特性,它允许开发者为类型提示附加运行时可访问的元数据。这对于需要额外信息(如验证规则、文档字符串、依赖注入提示等)的场景非常有用。例如,我们可以定义一个带有描述的 3D 点类型:
from typing import Annotated, tuple, list Point3D = Annotated[tuple[float, float, float], "A 3D Point"] Points = Annotated[list[Point3D], "A collection of points"]
然而,当这些带有注解的类型被嵌套使用时,它们的 repr() 表示会包含所有注解信息,这在某些情况下可能不是我们期望的。例如,直接打印 Points 会得到如下输出:
typing.Annotated[list[typing.Annotated[tuple[float, float, float], 'A 3D Point']], 'A collection of points']
如果我们只想获取其纯粹的类型结构,即 list[tuple[float, float, float]],而不包含任何注解信息,直接使用 typing.get_args() 往往不足以解决问题。例如,get_args(Points)[0] 会返回 list[typing.Annotated[tuple[float, float, float], 'A 3D Point']],内部的 Annotated 仍然存在。
要彻底剥离所有 Annotated 注解,我们需要一种能够深入到类型结构内部,识别并处理每一个 Annotated 节点的机制。最有效的方法是递归地遍历整个类型树。Python 的 typing 模块提供了 get_origin() 和 get_args() 函数,它们是实现这一目标的关键。
利用这两个函数,我们可以构建一个递归函数来遍历类型对象,并在遇到 Annotated 类型时,将其替换为其第一个类型参数(即实际类型),然后继续递归处理。
以下是实现此功能的 Python 函数:
from typing import Annotated, get_args, get_origin, TypeVar, Union
# 示例类型定义
Point3D = Annotated[tuple[float, float, float], "A 3D Point"]
Points = Annotated[list[Point3D], "A collection of points"]
ComplexType = Annotated[Union[Point3D, list[float]], "A complex type example"]
def convert_annotated_to_bare_types(type_object: type):
"""
递归地将类型对象中所有 typing.Annotated 节点转换为其裸类型。
Args:
type_object: 待处理的类型对象。
Returns:
移除了所有 Annotated 注解的裸类型对象。
"""
origin, args = get_origin(type_object), get_args(type_object)
# 1. 基础情况:如果不是泛型类型(没有 origin),直接返回
if origin is None:
return type_object
# 2. 处理 Annotated 类型:
# 如果是 Annotated,取其第一个参数(即实际类型),并递归处理
if origin is Annotated:
bare_type = get_args(type_object)[0]
return convert_annotated_to_bare_types(bare_type)
# 3. 处理其他泛型类型:
# 递归处理所有类型参数,然后使用原始类型和处理后的参数重建泛型
converted_args = [
convert_annotated_to_bare_types(arg) for arg in args
]
# 注意:对于像 TypeVar 这样的特殊类型,get_origin 会返回 TypeVar 本身,
# 但它没有 args,或者 args 已经被处理过。
# 这里的 origin(*converted_args) 语法适用于所有常见的泛型构造。
# 对于 TypeVar,get_origin 返回其自身,get_args 返回空,
# 所以 TypeVar() 依然是 TypeVar。
try:
return origin[*converted_args]
except TypeError:
# 某些特殊类型(如 TypeVar)可能不支持通过 origin[*args] 方式构造,
# 或者其 args 经过处理后不再符合原始类型的构造要求。
# 在这种情况下,我们尝试返回原始类型本身,或者根据具体情况进行更精细的处理。
# 对于本教程的 Annotated 剥离目的,如果遇到构造失败,
# 通常意味着这是一个不应被进一步解构的原子类型(如 TypeVar),
# 或者参数列表已不匹配。
# 简单起见,这里可以返回原始的 type_object,但更严谨可能需要根据 origin 判断。
# 针对 TypeVar,get_origin(TypeVar('T')) 会返回 TypeVar('T') 本身,
# get_args 会返回 (),所以 converted_args 也是 ()。
# origin[*()] 也就是 TypeVar('T')(),这会报错。
# 因此,对于 TypeVar 或类似情况,需要特殊处理。
if isinstance(origin, TypeVar): # 如果 origin 本身就是 TypeVar
return type_object # 直接返回原始 TypeVar
# 否则,尝试返回 origin,或者抛出异常以便调试
return origin 让我们使用前面定义的 Points 和 ComplexType 来测试这个函数:
# 原始类型
print(f"原始 Points 类型: {Points}")
print(f"原始 ComplexType 类型: {ComplexType}")
# 剥离注解后的类型
bare_points = convert_annotated_to_bare_types(Points)
print(f"剥离注解后的 Points: {bare_points}")
bare_complex_type = convert_annotated_to_bare_types(ComplexType)
print(f"剥离注解后的 ComplexType: {bare_complex_type}")
# 验证结果
# 期望输出: list[tuple[float, float, float]]
# 实际输出: list[tuple[float, float, float]] (取决于 Python 版本和内部表示)
# 注意:在某些 Python 版本中,tuple[float, float, float] 可能显示为 typing.Tuple[float, float, float]
# 但其语义是相同的。运行上述代码,你将看到如下输出(可能因Python版本略有差异):
原始 Points 类型: typing.Annotated[list[typing.Annotated[tuple[float, float, float], 'A 3D Point']], 'A collection of points'] 原始 ComplexType 类型: typing.Annotated[typing.Union[typing.Annotated[tuple[float, float, float], 'A 3D Point'], list[float]], 'A complex type example'] 剥离注解后的 Points: list[tuple[float, float, float]] 剥离注解后的 ComplexType: typing.Union[tuple[float, float, float], list[float]]
这完美地实现了我们的目标,从深层嵌套的 Annotated 类型中提取了纯粹的类型签名。
通过这种递归遍历的方法,我们能够有效地从复杂的 typing.Annotated 结构中提取出其核心的类型信息,为那些需要纯粹类型签名的场景提供了优雅而可靠的解决方案。
以上就是从 typing.Annotated 中递归剥离类型注解的教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号