Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In python, when you pass internally defined functions into other functions, how does it keep the variables?

For example, why does this work?

def func1(func1var):
    def innerfunc(innerfuncvar):
        if func1var == 1:
             print innerfuncvar
        else:
             print 5
    func2(innerfunc)


def func2(function):
     function(9)

When innerfunc is called in func2, how does it know the values of func1var?

like image 298
user e to the power of 2pi Avatar asked Aug 16 '11 13:08

user e to the power of 2pi


3 Answers

You've created a closure. Basically, think of it like this, from the point of view of the inner function:

func1var = whatever

def func2(function):
    function(9)

def innerfunc(innerfuncvar):
    if func1var = 1:
         print innerfuncvar
    else:
         print 5

func2(innerfunc)

It doesn't care whether func1var is in an outer or global scope -- it just looks for it in each scope outward, starting with it's own local scope. It's just like when you reference a module global variable from inside a class or function in that module.

like image 167
agf Avatar answered Oct 20 '22 23:10

agf


Python actually goes to some lengths to do this for you. When you define a function inside a function, you may use variables from the outer function in the inner function. This is true for any depth of nesting (that is, you can have a function inside a function inside a function inside a function... to any depth... and the innermost function can use variables from any of the enclosing functions). If there are conflicting names, the innermost variable with the name requested is used.

What's more, Python actually captures any variables you use from the outer function and stores them in the inner function, which is called a closure. So you can not only pass a function to another function, as you are doing, but you can return a function from a function, and variables you use from the outer function that were in effect when the function was defined will still be accessible from the returned function, even though the outer function isn't running any more. This is a fairly advanced feature, but it lets you do something like this:

def make_adder(increment):
    def adder(number):
        return number + increment
    adder.__name__ = "adder(%s)" % increment
    return adder

This function is a function that creates a function that adds the specified value to it. For example:

add1 = make_adder(1)
add5 = make_adder(5)

print add1(10)   # 11
print add5(10)   # 15

In this case, the value you pass to make_adder is captured and stored in the function that gets returned. This allows you to create a bunch of functions that add any number to their arguments. Which is a trivial example that isn't actually very useful in real life, but serves to illustrate the feature.

like image 6
kindall Avatar answered Oct 20 '22 23:10

kindall


Each time you call func1(func1var), Python actually builds a new function innerfunc(). Since func1var is perfectly defined when innerfunc() is created, the code of the new innerfunc() function contains the correct value of func1var.

like image 2
Eric O Lebigot Avatar answered Oct 20 '22 23:10

Eric O Lebigot