【问题标题】:Reference local type in pycontract在 pycontract 中引用本地类型
【发布时间】:2017-08-28 14:53:22
【问题描述】:

我正在尝试在 Web 应用程序中使用 PyContracts,因此我有很多自定义类被传递,我只是想与其他更传统的参数类型一起进行类型检查。为了清洁和强制文档,我想使用合同编程 (PyContracts) 来实现这一点。

当我按名称引用本地可见类时,PyContracts 似乎不知道该类型。例如:

from contracts import contract

class SomeClass:
    pass

@contract
def f(a):
    """

    :param a: Just a parameter
    :type a: SomeClass
    """
    print(a)

my_a = SomeClass()
f(my_a)

引发以下错误:

ContractSyntaxError: Unknown identifier 'SomeClass'. Did you mean 'np_complex64'? (at char 0), (line:1, col:1)

我知道我可以使用 new_contract 来自定义定义名称并将它们绑定到类,但是对于每种类型来说这样做都很麻烦。如果可能的话,我想使用 PyContracts 的 docstring 语法,而且我肯定需要使用字符串定义的合同格式,因为我使用的是布尔类型逻辑 ("None|str|SomeClass")。我如何使用本地类型和对其余代码库的最小入侵来实现这一点?

【问题讨论】:

    标签: python class contracts


    【解决方案1】:

    我拼凑了一个魔法装饰器,可以在创建合同之前添加类型。对于任何感兴趣的人来说,它似乎可以工作,但如果您定义大量函数,它可能会很慢:

    def magic_contract(*args, **kwargs):
        # Check if we got called without arguments, just the function
        func = None
        if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
            func = args[0]
            args = tuple()
    
        def inner_decorator(f):
            for name, val in f.__globals__.items():
                if isinstance(val, type):
                    new_contract(name, val)
            return contract(*args, **kwargs)(f)
    
        if func:
            return inner_decorator(func)
        return inner_decorator
    

    还有一些测试运行:

    In [3]: class SomeClass:
       ...:     pass
       ...:
    
    In [4]: @magic_contract
       ...: def f(a):
       ...:     """
       ...:
       ...:     :param a: Some parameter
       ...:     :type a: None|SomeClass
       ...:     """
       ...:     print(a)
       ...:
    
    In [5]: f(None)
    None
    
    In [6]: f(SomeClass())
    <__main__.SomeClass object at 0x7f1fa17c8b70>
    
    In [7]: f(2)
    ...
    ContractNotRespected: Breach for argument 'a' to f().
    ...
    
    In [8]: @magic_contract(b='int|SomeClass')
       ...: def g(b):
       ...:     print(type(b))
       ...:
    
    In [9]: g(2)
    <class 'int'>
    
    In [10]: g(SomeClass())
    <class '__main__.SomeClass'>
    
    In [11]: g(None)
    ...
    ContractNotRespected: Breach for argument 'b' to g().
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多