trouble with nested closures: one of my variables is missing...

Cameron Simpson cs at zip.com.au
Sun Oct 14 21:08:40 EDT 2012


On 14Oct2012 18:32, Ian Kelly <ian.g.kelly at gmail.com> wrote:
| On Sun, Oct 14, 2012 at 3:54 PM, Cameron Simpson <cs at zip.com.au> wrote:
| > |  You assign to it, but there's no nonlocal declaration, so Python thinks
| > | it's a local var, hence your error.
| >
| > But 'unset_object' is in locals(). Why one and not the other?
| > Obviously there's something about closures here I'm missing.
| 
| 'unset_object' is in locals because it's a free variable and those are
| included in locals(), and it has a value.
|
| 'attr_name' is not in locals because while it's a local variable, it
| has not been assigned to yet.  It has no value and an attempt to
| reference it at that point would result in an UnboundLocalError.

Can you elaborate a bit on that? The only place in my code that
unset_object is set is as a default parameter in make_file_property
(snippet):

  def make_file_property(attr_name=None, unset_object=None, poll_rate=1):
    print >>sys.stderr, "make_file_property(attr_name=%r, unset_object=%r, poll_rate=%r): locals()=%r" % (attr_name, unset_object, poll_rate,locals())
    def made_file_property(func):
      print >>sys.stderr, "made_file_property(func=%r): locals()=%r" % (func, locals())
      if attr_name is None:
        attr_name = '_' + func.__name__

and attr_name is set there also.

Is attr_name omitted from locals() in made_file_property _because_ I
have an assignment statement?

If that's the case, should I be doing this (using distinct names for the
closure variable and the function local variable):

  def make_file_property(attr_name=None, unset_object=None, poll_rate=1):
    print >>sys.stderr, "make_file_property(attr_name=%r, unset_object=%r, poll_rate=%r): locals()=%r" % (attr_name, unset_object, poll_rate,locals())
    def made_file_property(func):
      print >>sys.stderr, "made_file_property(func=%r): locals()=%r" % (func, locals())
      if attr_name is None:
        my_attr_name = '_' + func.__name__
      else:
        my_attr_name = attr_name
      lock_name = my_attr_name + '_lock'
      def getprop(self):
        with getattr(self, lock_name):
          pass
        return getattr(self, my_attr_name, unset_object)

i.e. deliberately _not_ assigning to attr_name as as to _avoid_ masking
the outer attr_name from the inner locals()?

BTW, doing that works. Is that The True Path for this situation?

If so, I think I now understand what's going on: Python has inspected
the inner function and not placed the outer 'attr_name' into locals()
_because_ the inner function seems to have its own local attr_name
in use, which should not be pre-tromped.

-- 
Cameron Simpson <cs at zip.com.au>

Nothing is so smiple that it can't get screwed up.



More information about the Python-list mailing list