Python:在inner方法中修改方法局部变量

时间:2016-02-12 17:09:57

标签: python-3.x scope globals python-nonlocal

我正在编写一个名为test_foo的测试方法(使用pytest)。我正在测试函数foo的行为,它将另一个函数get作为参数。 fooget的返回值有条件地调用get,例如:

def foo(get, param):
    max_num_tries = 3
    curr_num_tries = 0
    response = get(param)
    while curr_num_tries < max_num_tries and response.status_code == BAD_STATUS_CODE:
        response = get(param)
    return response

我试图覆盖get,以便它可以访问被调用的次数,并可以相应地返回不同的值。

这是我到目前为止的简化版本:

def test_foo():
    tries_so_far = 0

    def get(arg1):
        global tries_so_far
        if tries_so_far < 3:
            tries_so_far += 1
            print("do something special here")
        else:
            print("do something else here")
        return "some return val"

    foo(get, "some arg")

但是,我收到以下错误:

NameError: global name 'tries_so_far' is not defined

如果我在tries_so_far之外定义test_foo,则在模块级别,我会得到预期的行为。但是,我希望tries_so_far成为test_foo本地的变量。

是否有某种方法可以使用全局变量或其他技术对get进行tries_so_far读/写操作?注意:我无法更改get的参数或返回值。

1 个答案:

答案 0 :(得分:2)

根据此问题Why can functions in Python print variables in enclosing scope but cannot use them in assignment?的已接受答案,Python 3中添加了一个附加语句:nonlocal可以执行您想要的操作。它就像global,但是要查看封闭的范围而不是模块级别。因此,以下修改应该可以让您完全按照自己的意愿行事:

def test_foo():
    tries_so_far = 0

    def get(arg1):
        nonlocal tries_so_far
        if tries_so_far < 3:
            tries_so_far += 1
            print("do something special here")
        else:
            print("do something else here")
        return "some return val"

    foo(get, "some arg")

虽然您的问题与我上面引用的问题不完全相同,但您应该阅读接受的答案。这是非常好的,可能会解决你在这个问题上的许多未说明的问题。