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

Popular posts from this blog

asynchronous - C# WinSCP .NET assembly: How to upload multiple files asynchronously -

aws api gateway - SerializationException in posting new Records via Dynamodb Proxy Service in API -

asp.net - Problems sending emails from forum -