【问题标题】:Python decorator for checking the return type: Especially check for nested things like List[List[List[str]]]用于检查返回类型的 Python 装饰器:特别是检查嵌套的东西,如 List[List[List[str]]]
【发布时间】:2020-11-25 15:54:52
【问题描述】:

我正在尝试编写我的一个 python 装饰器来进行类型检查。它工作得很好,但在嵌套类型提示方面遇到了困难。例如采取

@type_check
def fun(x: int) -> List[List[List[str]]]:
    return [[[str(x)]]]

fun(x=42)

我有一个装饰器,它评估函数并检查实际返回值是否具有预期的类型:

import inspect
# inside the decorator
actual_result = func(*args, **kwargs)              # [[['42']]]
expected_result_type = spec.annotations['return']  # typing.List[typing.List[typing.List[str]]]

现在要检查的是[[['42']]] 的类型为typing.List[typing.List[typing.List[str]]]。 我该怎么做?

我发现,[[['42']]] 只需键入<class 'list'>,它完全忽略了有关嵌套的信息。 我可以检查一下

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

这适用于“外层”,但忽略嵌套类型提示。有什么方法可以检查所有图层吗?

【问题讨论】:

    标签: python python-3.x python-decorators python-typing


    【解决方案1】:

    简单的答案是:

    简单地递归到所有参数,例如:

    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)
    

    例子

    >>> type_check(5, int)
    True
    >>> type_check([1, 2, 3], typing.List[int])
    True
    >>> type_check([1, 2, 3], typing.List[float])
    False
    

    你可以简单地在你的装饰器中使用它。它可能会改进以处理 Dict、Tuple 和其他常见类型。

    然而这只是一个玩具示例,如果你想进行健壮的动态类型检查,你将不得不处理GeneratorCallableIterator 等...这不仅非常复杂而且在在某些情况下完全不可能(例如,除非迭代,否则无法检查迭代器)。

    看看enforce project 就是这样:使用装饰器的python 动态类型检查。 typing 模块源代码读起来也很有趣,但确实突破了动态自省的极限。

    希望对你有帮助;)

    【讨论】:

      猜你喜欢
      • 2021-11-25
      • 2022-01-09
      • 2015-02-19
      • 1970-01-01
      • 1970-01-01
      • 2019-08-08
      • 2016-08-21
      • 1970-01-01
      • 2014-12-20
      相关资源
      最近更新 更多