使用具有多个函数的闭包而不在Python中创建变量全局

时间:2013-10-10 05:06:47

标签: python closures

我正在尝试在Python 2.7中创建一个示例程序,它在两个函数之间保存/共享状态。 你调用一个函数,下次你调用一个函数时,它应该记住以前的值。这是我目前的代码:

def stuff():
    global x 
    x = 100
    def f():
        global x
        x = x * 2
        return x
    def g():
        global x
        x = x * 4
        return x
    return (f, g)

a,b = stuff()
print(a());

此代码有效,但问题是x不能被视为stuff()的范围之外的全局变量 ...(这就是重点首先在stuff()内嵌入x)。那么,x是全局的,还是stuff()的本地?

4 个答案:

答案 0 :(得分:2)

在Python 3.x中,您可以使用nonlocal语句:

def stuff():
    x = 100
    def f():
        nonlocal x
        x = x * 2
        return x
    def g():
        nonlocal x
        x = x * 4
        return x
    return f, g

>>> a, b = stuff()
>>> a()
200
>>> b()
800
>>> a()
1600

答案 1 :(得分:2)

如果你需要支持python 2.X,@ georgek的答案是最好的,但是很多人都没有意识到你可以为函数添加属性。一个常见的习惯用法是使用单个元素的列表来保存变量。

def stuff():
    x = [100]
    def g():
        x[0] = x[0]*2
        return x[0]
    def h():
        x[0] = x[0]*4
        return x[0]
    return (g,h)
a, b = stuff()
print(a())

这是有效的,因为你从不在内部作用域中分配x本身,所以它不会重新绑定变量并遮蔽闭包。

答案 2 :(得分:1)

最简单,最简单的解决方案,使用课程:

class stuff(object):
    x = 100
    def f(self):
        self.x = self.x * 2
        return self.x

    def g(self):
        self.x = self.x * 4
        return self.x

结果:

>>> s = stuff()
>>> s.f()
200
>>> s.g()
800

您希望阻止人们从功能外部访问x。你在Python中这样做的方法是在它前面添加一个下划线:

class stuff(object):
    _x = 100
    def f(self):
        self._x = self._x * 2
        return self._x

    def g(self):
        self._x = self._x * 4
        return self._x

这告诉其他Python程序员它是内部的,而不是访问它,除了他们自己的风险。你似乎想要阻止这一点,但你不能。您甚至可以在Python 3非本地示例中访问闭包:

def stuff():
    x = 100
    def f():
        nonlocal x
        x = x * 2
        return x

    return f

>>> a = stuff()
>>> a()
200
>>> a()
400
>>> a.__closure__[0].cell_contents
400

所以你并没有阻止任何人摆弄它,你只是让它变得晦涩难懂。而且更有可能失败。因此,你最终会让每个参与者都变得更加困难。

答案 3 :(得分:0)

您可以使用没有全局的功能:

>>> def f():
...     f.x = 100
...     def g():
...             f.x = f.x * 2
...             return f.x
...     def h():
...             f.x = f.x * 4
...             return f.x
...     return (g, h)
...
>>> a, b = f()
>>> a()
200
>>> b()
800
>>> a()
1600
>>>