nonlocal keyword in Python 2.x

2019-01-02 23:01发布

I'm trying to implement a closure in Python 2.6 and I need to access a nonlocal variable but it seems like this keyword is not available in python 2.x. How should one access nonlocal variables in closures in these versions of python?

10条回答
走好不送
2楼-- · 2019-01-02 23:17

Use a global variable

def outer():
    global y # import1
    y = 0
    def inner():
        global y # import2 - requires import1
        y += 1
        return y
    return inner

f = outer()
print(f(), f(), f()) #prints 1 2 3

Personally, I do not like the global variables. But, my proposal is based on https://stackoverflow.com/a/19877437/1083704 answer

def report():
        class Rank: 
            def __init__(self):
                report.ranks += 1
        rank = Rank()
report.ranks = 0
report()

where user needs to declare a global variable ranks, every time you need to call the report. My improvement eliminates the need to initialize the function variables from the user.

查看更多
贪生不怕死
3楼-- · 2019-01-02 23:19

The following solution is inspired by the answer by Elias Zamaria, but contrary to that answer does handle multiple calls of the outer function correctly. The "variable" inner.y is local to the current call of outer. Only it isn't a variable, since that is forbidden, but an object attribute (the object being the function inner itself). This is very ugly (note that the attribute can only be created after the inner function is defined) but seems effective.

def outer():
    def inner():
        inner.y += 1
        return inner.y
    inner.y = 0
    return inner

f = outer()
g = outer()
print(f(), f(), g(), f(), g()) #prints (1, 2, 1, 3, 2)
查看更多
霸刀☆藐视天下
4楼-- · 2019-01-02 23:19

There is another way to implement nonlocal variables in Python 2, in case any of the answers here are undesirable for whatever reason:

def outer():
    outer.y = 0
    def inner():
        outer.y += 1
        return outer.y
    return inner

f = outer()
print(f(), f(), f()) #prints 1 2 3

It is redundant to use the name of the function in the assignment statement of the variable, but it looks simpler and cleaner to me than putting the variable in a dictionary. The value is remembered from one call to another, just like in Chris B.'s answer.

查看更多
三岁会撩人
5楼-- · 2019-01-02 23:27

Rather than a dictionary, there's less clutter to a nonlocal class. Modifying @ChrisB's example:

def outer():
    class context:
        y = 0
    def inner():
        context.y += 1
        return context.y
    return inner

Then

f = outer()
assert f() == 1
assert f() == 2
assert f() == 3
assert f() == 4

Each outer() call creates a new and distinct class called context (not merely a new instance). So it avoids @Nathaniel's beware about shared context.

g = outer()
assert g() == 1
assert g() == 2

assert f() == 5
查看更多
登录 后发表回答