当嵌套函数被调用时,python如何记住封闭范围变量的值?

时间:2015-02-22 14:17:52

标签: python python-3.x scope

我读了一个关于闭包的例子

def outer():
        x = 1
        def inner():
           print x # 1
        return inner

变量x的生命周期直到函数外部运行的时间。 当我调用外部并返回内部地址时,变量x应该已经死亡,因为函数外部已经退出但仍然可以通过返回的内部函数来获取它吗?

python variable scope in nested functions

这个链接回答说,当外部将内部函数返回给调用者时,存储内部使用的变量的值,但是

现在看到这段代码

 def outer():
            x = 1
            def inner():
               print x*n # n not defined anywhere
            return inner

我运行了这段代码 当我调用outer时,这段代码不会给出任何错误,这意味着python在运行外部时不会检查内部函数使用的变量。那怎么知道它必须保留' x'退出后?

2 个答案:

答案 0 :(得分:3)

记住x的方式是因为python有一个特殊的__closure__属性,它记住了本地函数需要的封闭范围内的对象,并保留reference所以它可以用于本地函数:

def outer():
    x = 1
    def inner():
        print(x)
    return inner

o = outer()

print(o.__closure__)
(<cell at 0x7fa18a2fc588: int object at 0x9f8800>,)

如果您分配o = outer()然后调用o(),则调用inner函数,您将收到错误,调用outer()不会调用内部函数。

如果您要声明一个函数f并将print(n)置于正文中,那么除非您实际调用f,否则您将不会收到错误,因此相同的逻辑适用于您的内部函数,您实际上并没有使用outer()调用它,因此您不会收到错误:

def f():
    print(n) # will only error when we actually call `f()`

如果在调用inner时调用outer函数会导致失败,请考虑以下函数工厂,我们在其中使用指数e来提升i到:

def raise_exp(e):
    def power(i):
        return  i ** e # n not defined anywhere
    return power

sq = raise_exp(2) # set exponent but does not call power 
print(sq(2)) # now we actually all power
cube = raise_exp(3)
print(cube(3))

25
27

答案 1 :(得分:2)

  

变量x的生命周期直到函数外部运行

没有。 x只要可以从某个地方到达,就会活着。而且,它来自inner函数。

  

当我调用outer时,这段代码没有给出任何错误,这意味着python在运行外部时不会检查内部函数使用的变量

n可以在调用outer之后定义为,而调用其结果之前为 inner。在这种情况下,inner的身体是完全合法的。

如果您没有返回inner,那么就没有理由保留x,因为您无法inner,因此可以&x #39;以某种方式将{{1}}纳入计算。