[英]Python decorator for checking the return type: Especially check for nested things like List[List[List[str]]]
I'm trying to write my one python decorator for type checking.我正在尝试编写我的一个 python 装饰器来进行类型检查。 It works well, but struggles with nested type hints.
它工作得很好,但在嵌套类型提示方面遇到了困难。 For example take
例如采取
@type_check
def fun(x: int) -> List[List[List[str]]]:
return [[[str(x)]]]
fun(x=42)
I have a decorator, which eveluates the function and checks, if the actual return value has the expected type:我有一个装饰器,它评估 function 并检查实际返回值是否具有预期的类型:
import inspect
# inside the decorator
actual_result = func(*args, **kwargs) # [[['42']]]
expected_result_type = spec.annotations['return'] # typing.List[typing.List[typing.List[str]]]
And now is challenge to check is [[['42']]]
has type typing.List[typing.List[typing.List[str]]]
.现在检查的挑战是
[[['42']]]
有类型typing.List[typing.List[typing.List[str]]]
。 How can I do that?我怎样才能做到这一点?
All I found out, is that [[['42']]]
has simply type <class 'list'>
which ignores the information about nesting completly.我发现,
[[['42']]]
只是简单地键入<class 'list'>
,它完全忽略了有关嵌套的信息。 And I can check this with我可以检查一下
if hasattr(expected_result_type, '__origin__'):
expected_result_type = expected_result_type.__origin__
if expected_result_type is not None:
assert isinstance(result, expected_result_type)
else: # None is kind of a special case
assert result is expected_result_type
This works on the "outer layer", but ignores nested type hints.这适用于“外层”,但忽略嵌套类型提示。 Is there any way to check all layers?
有什么方法可以检查所有图层吗?
The simple answer would be:简单的答案是:
Simply recurse into all arguments like:简单地递归到所有 arguments 像:
def type_check(value, annotation):
if isinstance(annotation, type):
return isinstance(value, annotation)
elif annotation == typing.T or annotation == typing.Any:
return True
elif isinstance(annotation, typing._GenericAlias):
if annotation.__origin__ == list:
if not isinstance(value, list):
return False
inner_annotation = annotation.__args__[0]
return all(type_check(val, inner_annotation) for val in value)
Example例子
>>> type_check(5, int)
True
>>> type_check([1, 2, 3], typing.List[int])
True
>>> type_check([1, 2, 3], typing.List[float])
False
Which you can simply use in you decorator.你可以简单地在你的装饰器中使用它。 It might be improved to handle Dict, Tuple and other common types.
它可能会改进以处理 Dict、Tuple 和其他常见类型。
However it's just a toy example, if you want to do robust dynamic type checking, you'll have to handle Generator
, Callable
, Iterator
etc... which is not only quite complex but also in some case completely impossible (Iterators for example can't be checked unless iterated over).然而,这只是一个玩具示例,如果你想进行健壮的动态类型检查,你将不得不处理
Generator
、 Callable
、 Iterator
等......这不仅非常复杂,而且在某些情况下完全不可能(例如 Iterators 可以'除非迭代,否则不会被检查)。
Have a look at the enforce project which is exactly that: a python dynamic type checking using decorators.看看enforce 项目,它就是这样:使用装饰器的python 动态类型检查。 The
typing
module source code is also really interesting to read, but really pushes the limits of what dynamic introspection can do. typing
模块的源代码读起来也很有趣,但确实突破了动态自省的极限。
Hope it helps;)希望能帮助到你;)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.