PyContract PostCondition涉及非输入参数变量

时间:2012-10-24 04:26:40

标签: python design-by-contract invariants

希望这将是我在系列中的最后一个问题(我的项目几乎结束了,除非要求发生变化)。

我正在使用PyContract(不是PyContracts)为类方法编写一些约束。在我的一个职能中,我有一个不变的。但是,并非构成此后置条件的所有变量都是函数的输入参数;一些是函数本身范围内的变量(循环计数器等)。我如何/可以在合同的后置条款中捕获它们?

以下是我一直在使用的MWE代码:

def foo(*args, **kwargs):
    """
        pre:
            # some preconditions
        inv:
            # something that's clearly false
            1 == 2
        post:
            g < arg5
    """

    arg1 = kwargs['arg1']
    arg2 = kwargs['arg2']
    arg3 = kwargs['arg3']
    arg4 = kwargs['arg4']
    arg5 = kwargs['arg5']

    g = 0
    while g < arg5:
        vars = generate_data(arg1)
        best = max(arg2(var)for var in vars)
        if best >= arg3:
            return best
        # do stuff
        g += 1

当PyContract告诉我它不知道名字garg5时,会出现问题。我在合同中将arg5更改为kwargs['arg5'],但PyContract仍然不知道g是什么。我怎么能解决这个问题?

我得到的错误是:

Traceback (most recent call last):
  File "/Users/ashwin/github/local/Genetic-Framework/Genetic-Framework/Genetic/GA.py", line 245, in <module>
    answer = runTSPGA(*settings, **settings)
  File "<string>", line 3, in __assert_runTSPGA_chk
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/contract.py", line 1135, in call_public_function_all
    return _call_one_all(func, va, ka)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/contract.py", line 1321, in _call_one_all
    func.__assert_post(old, result, *va, **ka)
  File "<string>", line 4, in __assert_runTSPGA_post
NameError: global name 'g' is not defined

g添加到后置条件声明中,如下所示也无济于事:

post[kwargs, g]:

此外,有趣的是,不变检查的代码似乎根本没有运行

1 个答案:

答案 0 :(得分:0)

在函数完成运行后运行后置条件,这意味着包含函数本地(例如arg5g)的堆栈帧不再在范围内。

对于实现契约的库来说,这并不令人惊讶:重点是在函数应该实现的接口上声明约束,而你似乎想要检查函数的内部状态是什么没有在返回值中显示。

您可以采取的两种方式:

  1. 使函数返回要与合同一起检查的状态。如果内部状态不是函数接口的一部分,这可能不合适。

  2. 使用除PyContracts之外的其他内容来强制执行约束,例如assert语句,或循环后的raise AssertionError("while loop should have returned early")语句。