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