scope - Local variables in Python nested functions -
okay, bear me on this, know it's going horribly convoluted, please me understand what's happening.
from functools import partial class cage(object): def __init__(self, animal): self.animal = animal def gotimes(do_the_petting): do_the_petting() def get_petters(): animal in ['cow', 'dog', 'cat']: cage = cage(animal) def pet_function(): print "mary pets " + cage.animal + "." yield (animal, partial(gotimes, pet_function)) funs = list(get_petters()) name, f in funs: print name + ":", f() gives:
cow: mary pets cat. dog: mary pets cat. cat: mary pets cat. so basically, why not getting 3 different animals? isn't cage 'packaged' local scope of nested function? if not, how call nested function local variables?
i know running these kind of problems means 1 'doing wrong', i'd understand happens.
the nested function looks variables parent scope when executed, not when defined.
the function body compiled, , 'free' variables (not defined in function assignment), verified, bound closure cells function, code using index reference each cell. pet_function has one free variable (cage) referenced via closure cell, index 0. closure points local variable cage in get_petters function.
when call function, closure used @ value of cage in surrounding scope at time call function. here lies problem. time call functions, get_petters function done computing it's results. cage local variable @ point during execution assigned each of 'cow', 'dog', , 'cat' strings, @ end of function, cage contains last value 'cat'. thus, when call each of dynamically returned functions, value 'cat' printed.
the work-around not rely on closures. can use partial function instead, create new function scope, or bind variable default value keyword parameter.
partial function example, using
functools.partial():from functools import partial def pet_function(cage=none): print "mary pets " + cage.animal + "." yield (animal, partial(gotimes, partial(pet_function, cage=cage)))creating new scope example:
def scoped_cage(cage=none): def pet_function(): print "mary pets " + cage.animal + "." return pet_function yield (animal, partial(gotimes, scoped_cage(cage)))binding variable default value keyword parameter:
def pet_function(cage=cage): print "mary pets " + cage.animal + "." yield (animal, partial(gotimes, pet_function))
there no need define scoped_cage function in loop, compilation takes place once, not on each iteration of loop.
Comments
Post a Comment