验证Python“输入”注释

时间:2017-09-01 16:50:58

标签: python

我想使用typing在函数调用之外的运行时验证数据结构。但是,我不确定如何检查两个typing类型是否兼容。似乎typing类型与isinstance不能很好地匹配。

目标是定义使用描述符对赋值进行类型检查的类属性。

以下是一个例子:

class MyStruct(object, metaclass=MyStructMeta):
    a = List[int]

my_struct = MyStruct()
my_struct.a = [1]
my_struct.a = ['a']  # should assert

现在,我很清楚如何编写使这项工作所需的描述符和元类。但是,我不确定如何验证分配给属性的值是否符合typing定义。

2 个答案:

答案 0 :(得分:0)

我支持我在评论中所说的内容 - 不应该为typing模块中的所有内容实现此功能。我想不出任何方法可靠地为不可信的可调用或可消耗的迭代器实现这个(如果它希望你发送一些东西怎么办?你怎么知道要发送什么?)。但是,对于基本类型的嵌套列表,我提出了这种递归解决方案:

from typing import *

def is_type(var, typ):
    if issubclass(typ, list):
        if isinstance(var, list):
            subtype, = typ.__args__
            return all(is_type(i, subtype) for i in var)
        return False
    return isinstance(var, typ)

我用以下方法对其进行了测试:

print("should all be True:")
print(is_type(1, int))
print(is_type([1, 2, 3], List[int]))
print(is_type([[1, 2], [3, 4], [5, 6]], List[List[int]]))
print(is_type("a", str))
print(is_type(["a", "bc", "d"], List[str]))
print(is_type([["a", "bc"], ["d", "e"]], List[List[str]]))
print(is_type([], List[int]))
print(is_type([], List[List[str]]))
print(is_type([[]], List[List[int]]))

print("should all be False:")
print(is_type(1, str))
print(is_type([1, "2", 3], List[int]))
print(is_type(3, List[int]))
print(is_type([["a", 2], [3, 4], [5, 6]], List[List[int]]))
print(is_type([[1, 2], [3, 4], 56], List[List[int]]))
print(is_type([[]], List[int]))

我的机器上的行为正确。如果您要执行此操作,则会抛出TypeError:

is_type(lambda x: x**2, Callable[[int], int])

答案 1 :(得分:0)

typing模块不会验证您的类型;它只是在builtins模块中已有的提供更多抽象类型(例如ListSetOptional等)。

为了验证您的代码,您应该使用可以理解Python类型提示的linter,例如MyPy

例如,如果您将代码保存到文件/tmp/test.py

from typing import List


class MyStruct(object):
    a: List[int]


my_struct = MyStruct()
my_struct.a = [1]
my_struct.a = ['a']  # should assert

运行python -m pypy test.py会出现以下错误:

tmp/test.py:10: error: List item 0 has incompatible type "str"