假设我有一些类型别名,也许
Point3D = Annotated[tuple[float, float, float], "A 3D Point"]
Points = Annotated[list[Point3D, list[float]], "A collection of points"]
如果我尝试打印积分,我会得到
typing.Annotated[list[typing.Annotated[tuple[float, float, float], 'A 3D Point'], list[float]], 'A collection of points']
我只想得到
list[tuple[float, float, float]]
部分。我尝试使用 typing.get_args(Points)[0]
但这只是给出了这个:
list[typing.Annotated[tuple[float, float, float], 'A 3D Point'], list[float]]
仍然存在不需要的
'A 3D Point'
。我怎样才能实现这个目标?我尝试将其替换为 ", '.*?'
正则表达式,但这不起作用,而且我对正则表达式的经验不足,无法找出原因。
注意: 我不能只是将所有
Annotated
类型更改为普通类型提示,因为我仍然需要在其他地方显示注释内容。
解决方案很简单:遍历树(在运行时)并将所有
Annotated
节点转换为其裸类型对应节点。不需要正则表达式。
from typing import Annotated, get_args, get_origin
def convert_annotated_to_bare_types(type_object: type):
# For a given `X[Y, Z, ...]`:
# * `get_origin` returns `X`
# * `get_args` return `(Y, Z, ...)`
# For non-supported type objects, the return values are
# `None` and `()` correspondingly.
origin, args = get_origin(type_object), get_args(type_object)
if origin is None:
# No origin -> Not a generic/no arguments.
return type_object
if origin is Annotated:
# Annotated -> Convert the first argument recursively.
bare_type = get_args(type_object)[0]
return convert_annotated_to_bare_types(bare_type)
# Otherwise, it is a generic. Convert all arguments recursively.
converted_args = [
convert_annotated_to_bare_types(arg) for arg in args
]
return origin[*converted_args]
它的工作原理与您所期望的完全一样,即使
list
不应该采用 2 个类型参数:
>>> convert_annotated_to_bare_types(Points)
list[tuple[float, float, float], list[float]]