python variable scope in nested functions

2019-04-07 14:38发布

I am reading this article about decorator.

At Step 8 , there is a function defined as:

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

and if we run it by:

>>> foo = outer()
>>> foo.func_closure # doctest: +ELLIPSIS

it doesn't print x. According to the explanation :

Everything works according to Python’s scoping rules - x is a local variable in our function outer. When inner prints x at point #1 Python looks for a local variable to inner and not finding it looks in the enclosing scope which is the function outer, finding it there.

But what about things from the point of view of variable lifetime? Our variable x is local to the function outer which means it only exists while the function outer is running. We aren’t able to call inner till after the return of outer so according to our model of how Python works, x shouldn’t exist anymore by the time we call inner and perhaps a runtime error of some kind should occur.

However, I don't really understand what the second paragraph means.

I understand inner() does get the value of x but why it doesn't print x out?

thanks

UPDATE:

Thanks all for the answers. Now I understand the reason. the "return inner" is just a pointer to inner() but it doesn't get executed, that is why inner() doesn't print x as it is not called at all

2条回答
SAY GOODBYE
2楼-- · 2019-04-07 15:09

You are not calling inner. You have called outer, which returns inner, but without calling it. If you want to call inner, do foo() (since you assinged the result of outer() to the name foo).

The paragraph you quoted is sort of tangential to this issue. You say you already understand why inner gets the value of x, which is what that paragraph is explaining. Basically, if a local variable is used in a nested function, and that nested function is returned, the value of the variable is stored along with the returned function, even if the scope where that variable was defined in no longer active. Normally x would be gone after outer finished, because x is just local to outer. But outer returns inner, which still needs access to x. So x gets wrapped up into what's called a closure, so it can still be accessed by inner later on.

查看更多
Emotional °昔
3楼-- · 2019-04-07 15:25

I understand inner() does get the value of x but why it doesn't print x out?

It doesn't print out anything because you've not called the inner function yet.

>>> def outer():
        x = 1
        def inner():
               print x # 1
        return inner
...     
>>> func = outer()  
>>> func            
<function inner at 0xb61e280c>
>>> func()
1

This is called a closure, i.e even though the outer function is not in stack(finished executing) anymore but still the inner function that was returned from it remembers it's state.(i.e value of x)

>>> def outer():
            x = 1
            y = 2
            def inner():
                    z=3
                    print x
            return inner
...     
>>> func = outer()
>>> func.func_code.co_freevars  #returns the variables that were used in closure
('x',)

From the source code on how python decides it's a closure or not:

   459    if len(code.co_freevars) == 0:
   460        closure = NULL
   461    else:
   462        len(closure) == len(code.co_freevars)

In py3.x you can also modify the value of x using nonlocal statement inside inner function.

>>> def outer():
        x = 1
        def inner():
           nonlocal x
           x += 1
           print (x)
        return inner
...     
>>> func = outer()
>>> func()
2
>>> func()
3
>>> func()
4
查看更多
登录 后发表回答