python3.9的typing.Annotation的MaxLen如何使用?
How to use MaxLen of typing.Annotation of python 3.9?
我知道有这种新的输入格式 Annotated
,您可以在其中为函数的入口变量指定一些元数据。 From the docs,您可以指定传入列表的最大长度,例如:
- Annotated can be used with nested and generic aliases:
T = TypeVar('T')
Vec = Annotated[list[tuple[T, T]], MaxLen(10)]
V = Vec[int]
V == Annotated[list[tuple[int, int]], MaxLen(10)]
但我无法理解MaxLen
是什么。您应该从其他地方导入 class 吗?我试过导入 typing.MaxLen
但似乎不存在(我正在使用 Python 3.9.6,which I think it should exist here...?)。
我想象中应该有效的示例代码:
from typing import List, Annotated, MaxLen
def function(foo: Annotated[List[int], MaxLen(10)]):
# ...
return True
在哪里可以找到 MaxLen
?
编辑:
似乎 MaxLen
是您必须创建的某种 class。问题是我看不到你应该怎么做。有public个例子吗?谁能实现这个功能?
如 AntiNeutronicPlasma 所述,Maxlen
只是一个示例,您需要自己创建。
下面是如何创建和解析自定义注释的示例,例如 MaxLen
以帮助您入门。
首先,我们定义注解class本身。很简单class,我们只需要存储相关的元数据,在本例中,最大值:
class MaxLen:
def __init__(self, value):
self.value = value
现在,我们可以定义一个使用这个注解的函数,例如:
def sum_nums(nums: Annotated[List[int], MaxLen(10)]):
return sum(nums)
但是如果没有人检查它就没什么用了。因此,一种选择是实现一个在运行时检查您的自定义注释的装饰器。来自 typing
模块的函数 get_type_hints
、get_origin
和 get_args
将成为您最好的朋友。下面是这样一个装饰器的例子,它在 list
类型上解析并强制执行 MaxLen
注释:
from functools import wraps
from typing import get_type_hints, get_origin, get_args, Annotated
def check_annotations(func):
@wraps(func)
def wrapped(**kwargs):
# perform runtime annotation checking
# first, get type hints from function
type_hints = get_type_hints(func, include_extras=True)
for param, hint in type_hints.items():
# only process annotated types
if get_origin(hint) is not Annotated:
continue
# get base type and additional arguments
hint_type, *hint_args = get_args(hint)
# if a list type is detected, process the args
if hint_type is list or get_origin(hint_type) is list:
for arg in hint_args:
# if MaxLen arg is detected, process it
if isinstance(arg, MaxLen):
max_len = arg.value
actual_len = len(kwargs[param])
if actual_len > max_len:
raise ValueError(f"Parameter '{param}' cannot have a length "
f"larger than {max_len} (got length {actual_len}).")
# execute function once all checks passed
return func(**kwargs)
return wrapped
(请注意,此特定示例仅适用于关键字参数,但您可能会找到一种方法使其也适用于普通参数)。
现在,您可以将此装饰器应用于任何函数,您的自定义注释将得到解析:
from typing import Annotated, List
@check_annotations
def sum_nums_strict(nums: Annotated[List[int], MaxLen(10)]):
return sum(nums)
下面是代码的一个例子:
>>> sum_nums(nums=list(range(5)))
10
>>> sum_nums(nums=list(range(15)))
105
>>> sum_nums_strict(nums=list(range(5)))
10
>>> sum_nums_strict(nums=list(range(15)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "annotated_test.py", line 29, in wrapped
raise ValueError(f"Parameter '{param}' cannot have a length "
ValueError: Parameter 'nums' cannot have a length larger than 10 (got length 15).
我知道有这种新的输入格式 Annotated
,您可以在其中为函数的入口变量指定一些元数据。 From the docs,您可以指定传入列表的最大长度,例如:
- Annotated can be used with nested and generic aliases:
T = TypeVar('T')
Vec = Annotated[list[tuple[T, T]], MaxLen(10)]
V = Vec[int]
V == Annotated[list[tuple[int, int]], MaxLen(10)]
但我无法理解MaxLen
是什么。您应该从其他地方导入 class 吗?我试过导入 typing.MaxLen
但似乎不存在(我正在使用 Python 3.9.6,which I think it should exist here...?)。
我想象中应该有效的示例代码:
from typing import List, Annotated, MaxLen
def function(foo: Annotated[List[int], MaxLen(10)]):
# ...
return True
在哪里可以找到 MaxLen
?
编辑:
似乎 MaxLen
是您必须创建的某种 class。问题是我看不到你应该怎么做。有public个例子吗?谁能实现这个功能?
如 AntiNeutronicPlasma 所述,Maxlen
只是一个示例,您需要自己创建。
下面是如何创建和解析自定义注释的示例,例如 MaxLen
以帮助您入门。
首先,我们定义注解class本身。很简单class,我们只需要存储相关的元数据,在本例中,最大值:
class MaxLen:
def __init__(self, value):
self.value = value
现在,我们可以定义一个使用这个注解的函数,例如:
def sum_nums(nums: Annotated[List[int], MaxLen(10)]):
return sum(nums)
但是如果没有人检查它就没什么用了。因此,一种选择是实现一个在运行时检查您的自定义注释的装饰器。来自 typing
模块的函数 get_type_hints
、get_origin
和 get_args
将成为您最好的朋友。下面是这样一个装饰器的例子,它在 list
类型上解析并强制执行 MaxLen
注释:
from functools import wraps
from typing import get_type_hints, get_origin, get_args, Annotated
def check_annotations(func):
@wraps(func)
def wrapped(**kwargs):
# perform runtime annotation checking
# first, get type hints from function
type_hints = get_type_hints(func, include_extras=True)
for param, hint in type_hints.items():
# only process annotated types
if get_origin(hint) is not Annotated:
continue
# get base type and additional arguments
hint_type, *hint_args = get_args(hint)
# if a list type is detected, process the args
if hint_type is list or get_origin(hint_type) is list:
for arg in hint_args:
# if MaxLen arg is detected, process it
if isinstance(arg, MaxLen):
max_len = arg.value
actual_len = len(kwargs[param])
if actual_len > max_len:
raise ValueError(f"Parameter '{param}' cannot have a length "
f"larger than {max_len} (got length {actual_len}).")
# execute function once all checks passed
return func(**kwargs)
return wrapped
(请注意,此特定示例仅适用于关键字参数,但您可能会找到一种方法使其也适用于普通参数)。
现在,您可以将此装饰器应用于任何函数,您的自定义注释将得到解析:
from typing import Annotated, List
@check_annotations
def sum_nums_strict(nums: Annotated[List[int], MaxLen(10)]):
return sum(nums)
下面是代码的一个例子:
>>> sum_nums(nums=list(range(5)))
10
>>> sum_nums(nums=list(range(15)))
105
>>> sum_nums_strict(nums=list(range(5)))
10
>>> sum_nums_strict(nums=list(range(15)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "annotated_test.py", line 29, in wrapped
raise ValueError(f"Parameter '{param}' cannot have a length "
ValueError: Parameter 'nums' cannot have a length larger than 10 (got length 15).