문제

I am trying to understand, how exactly variable binding in python works. Let's look at this:

def foo(x):
    def bar():
        print y
    return bar

y = 5
bar = foo(2)
bar()

This prints 5 which seems reasonable to me.

def foo(x):
    def bar():
        print x
    return bar
x = 5
bar = foo(2)
bar()

This prints 2, which is strange. In the first example python looks for the variable during execution, in the second when the method is created. Why is it so?

To be clear: this is very cool and works exactly as I would like it to. However, I am confused about how internal bar function gets its context. I would like to understand, what happens under the hood.

EDIT

I know, that local variables have greater priority. I am curious, how python knows during execution to take the argument from a function I have called previously. bar was created in foo and x is not existing any more. It have bound this x to the argument value when function was created?

도움이 되었습니까?

해결책

The second example implements what is called a closure. The function bar is referencing the variable x from its surrounding context, i.e. the function foo. This precedes the reference to the global variable x.

See also this question Can you explain closures (as they relate to Python)?

다른 팁

The issue that you are alluding to is one of lexical vs dynamic scoping of variables in python. To be explicit, python defines the following four scopes.

  1. The innermost scope, which is searched first, contains the local names
  2. The scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names
  3. the next-to-last scope contains the current module’s global names
  4. the outermost scope (searched last) is the namespace containing built-in names

In the first example, where "y" is defined outside of the function bar, python searched for the innermost scope and moved up the chain until it found the global variable "y" in the module

In the second example, where "x" is being defined by function foo(x), x belongs to the scope of an enclosing function, when its being printed inside bar. In pure terms, a closure has been defined.

For further study on scoping in python, I found the following article a great read

In both examples, the lookup happens at runtime. The only difference is that there's a locally defined variable x, while there isn't a locally defined variable y.

When executing ...

def foo(x):
    def bar():
        print y

    return bar

y = 5
bar = foo(2)
bar()

... the print statement looks up the variable named y, and only finds it in the global context, so it uses that one, and prints "5".

In ...

def foo(x):
    def bar():
        print x

    return bar

x = 5
bar = foo(2)
bar()

... when the lookup occurs, there is a scoped variable x defined--which is fixed at "5" when the foo function is called.

The key is that arguments are evaluated at the time they're passed into functions, so the outer function foo evaluates the arguments passed in when it's called. This effectively creates a variable called x in the context of the foo function, so whenever bar executes it sees that variable, and not the globally defined one.

This can occasionally be confusing, as in the following code:

lst = []
for i in range(5):
    x = i
    lst.append(lambda: x)

for func in lst:
    print func()  # prints 4 4 4 4 4

You need to do:

lst = []
for i in range(5):
    def _func(x):
        return lambda: x

    lst.append(_func(i))

for func in lst:
    print func()  # prints 0 1 2 3 4

Nothing strange, it is because "x" from function argument has higher priority than global variable "x".

At first, global variables is a great evil.

Python has operator "global":

>>> def foo(x):
...     def bar():
...          global x
...          print x
...     return bar
... 
>>> x = 5
>>> bar = foo(2)
>>> bar()
5

It is mater of scope, second example uses local scope variable x, that is preceded above globally declared

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top