在 pycontract 中引用本地类型
Reference local type in pycontract
我正在尝试在 Web 应用程序中使用 PyContracts,所以我有很多自定义的 classes 被传递,我只是想与其他更传统的参数类型一起进行类型检查。为了清洁和强制文档,我想使用合同编程 (PyContracts) 来完成此操作。
当我按名称引用本地可见的 class 时,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 来自定义名称并将它们绑定到 classes,但是对于每种类型来说这都是一件很麻烦的事情。如果可能的话,我想对 PyContracts 使用 docstring 语法,而且我肯定需要使用字符串定义的合同格式,因为我使用的是布尔类型逻辑 ("None|str|SomeClass"
)。我如何使用本地类型完成此操作并最大限度地减少对我的代码库其余部分的干扰?
我破解了一个神奇的装饰器,可以在创建合同之前添加类型。对于任何感兴趣的人,它似乎都有效,但如果您定义大量函数,它可能会很慢:
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().
...
我正在尝试在 Web 应用程序中使用 PyContracts,所以我有很多自定义的 classes 被传递,我只是想与其他更传统的参数类型一起进行类型检查。为了清洁和强制文档,我想使用合同编程 (PyContracts) 来完成此操作。
当我按名称引用本地可见的 class 时,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 来自定义名称并将它们绑定到 classes,但是对于每种类型来说这都是一件很麻烦的事情。如果可能的话,我想对 PyContracts 使用 docstring 语法,而且我肯定需要使用字符串定义的合同格式,因为我使用的是布尔类型逻辑 ("None|str|SomeClass"
)。我如何使用本地类型完成此操作并最大限度地减少对我的代码库其余部分的干扰?
我破解了一个神奇的装饰器,可以在创建合同之前添加类型。对于任何感兴趣的人,它似乎都有效,但如果您定义大量函数,它可能会很慢:
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().
...