Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python and closed variables

Have a look at this code:

def closure():
    value = False

    def method_1():
        value = True

    def method_2():
        print 'value is:', value

    method_1()
    method_2()

closure()

I would expect it to print 'Value is: True' but it doesn't. Why is this and what is the solution?

like image 978
Lee Treveil Avatar asked Jul 26 '11 14:07

Lee Treveil


People also ask

What is a closed over variable Python?

A closure is a nested function which has access to a free variable from an enclosing function that has finished its execution. Three characteristics of a Python closure are: it is a nested function. it has access to a free variable in outer scope. it is returned from the enclosing function.

Does Python allow closures?

Python Decorators make an extensive use of closures as well. On a concluding note, it is good to point out that the values that get enclosed in the closure function can be found out. All function objects have a __closure__ attribute that returns a tuple of cell objects if it is a closure function.

Why do we use closures in Python?

The closure can have the following advantages: We can avoid the use of global values by calling the local function outside its scope, and accessing the enclosed variable outside its scope. It is great for hiding data in your programs and is highly used while building python microservices.

How do closures work in Python?

Closure in Python is an inner function object, a function that behaves like an object, that remembers and has access to variables in the local scope in which it was created even after the outer function has finished executing.


2 Answers

This happens because method_1 gets its own local scope where it can declare variables. Python sees value = True and thinks you're creating a new variable named value, local to method_1.

The reason Python does this is to avoid polluting the outer scope's locals with variables from an inner function. (You wouldn't want assignments in regular, module-level functions to result in global variables being created!)

If you don't assign to value, then Python searches the outer scopes looking for the variable (so reading the variable works as expected, as demonstrated by your method_2).

One way to get around this is by using a mutable object instead of assigment:

result = { 'value': False }

def method_1():
    result['value'] = True

In Python 3, the nonlocal statement (see also docs) was added for exactly this scenario:

def method_1():
    nonlocal value
    value = True    # Works as expected -- assigns to `value` from outer scope
like image 145
Cameron Avatar answered Sep 29 '22 05:09

Cameron


In method_1, Python assumes (quite sensibly!) that value is a local variable. Whenever you assign to a variable name inside a function, it is assumed that that variable name is a new local variable. If you want it to be global, then you have to declare it as global, and if you want it to be "nonlocal", in Python 3, you can declare it nonlocal, but in Python 2, you have to do something uglier: store the value in a container. That avoids having to reassign the variable name, and so avoids the scoping ambiguity.

def method_1_global():
    global value
    value = True

def method_1_nonlocal_P3():
    nonlocal value
    value = True

value = [False]
def method_1_nonlocal_P2():
    value[0] = True
like image 34
senderle Avatar answered Sep 29 '22 05:09

senderle