A nested function looks for variables from the parent scope when it is executed, and not when defined.
The body of the function is compiled, and the "free" variables (not defined in the function itself for the purpose) are checked and then linked as trailing cells to the function, and the code uses the index to refer to each cell. pet_function thus, pet_function has one free variable ( cage ), which is then referenced through the closure cell, index 0. The closure itself points to the local cage variable in the get_petters function.
When you actually call a function, this closure is then used to view the cage value in the surrounding area at the time the function was called. This is where the problem lies. By the time you call your functions, the get_petters function get_petters already running, evaluating it. At one point during this execution, the local cage variable was assigned to each of the lines 'cow' , 'dog' and 'cat' , but at the end of this function, cage contains the last value of 'cat' . Thus, when you call each of the dynamically returned functions, you get the value 'cat' .
A workaround is not to rely on closure. Instead, you can use a partial function, create a new function area, or bind a variable as the default value for a keyword parameter.
An example of a partial function using functools.partial() :
from functools import partial def pet_function(cage=None): print "Mary pets the " + cage.animal + "." yield (animal, partial(gotimes, partial(pet_function, cage=cage)))
An example of creating a new area:
def scoped_cage(cage=None): def pet_function(): print "Mary pets the " + cage.animal + "." return pet_function yield (animal, partial(gotimes, scoped_cage(cage)))
Binding a variable as the default value for a keyword parameter:
def pet_function(cage=cage): print "Mary pets the " + cage.animal + "." yield (animal, partial(gotimes, pet_function))
There is no need to define the scoped_cage function in a loop; compilation is performed only once, and not at each iteration of the loop.
Martijn Pieters Sep 14 '12 at 11:37 2012-09-14 11:37
source share