On Saturday, October 13, 2012, Cameron Simpson  wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I'm having some trouble with closures when defining a decorator.</blockquote>
<div><snip> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
However, I can't make my make_file_property function work. I've stripped<br>
the code down and it does this:</blockquote><div><snip> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  Traceback (most recent call last):<br>
    File "foo.py", line 21, in <module><br>
      def f(self, foo=1):<br>
    File "foo.py", line 4, in file_property<br>
      return make_file_property()(func)<br>
    File "foo.py", line 10, in made_file_property<br>
      if attr_name is None:<br>
  UnboundLocalError: local variable 'attr_name' referenced before assignment<br>
<br>
Observe above that 'unset_object' is in locals(), but not 'attr_name'.<br>
This surprises me.<br>
<br>
The stripped back code (missing the internals of the file property<br>
watcher) looks like this:<br>
<br>
  import sys<br>
<br>
  def file_property(func):<br>
    return make_file_property()(func)<br>
<br>
  def make_file_property(attr_name=None, unset_object=None, poll_rate=1):<br>
    print >>sys.stderr, "make_file_property(attr_name=%r, unset_object=%r, poll_rate=%r): locals()=%r" % (attr_name, unset_object, poll_rate,locals())<br>
    def made_file_property(func):</blockquote><div><span style><br></span></div><div><span style>You're missing a "nonlocal" declaration here.</span><br dir="ltr"></div><div><span style><br></span></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

      print >>sys.stderr, "made_file_property(func=%r): locals()=%r" % (func, locals())<br>
      if attr_name is None:<br>
        attr_name = '_' + func.__name__</blockquote><div><br></div><div> You assign to it, but there's no nonlocal declaration, so Python thinks it's a local var, hence your error.</div><div><br></div><div>
Pardon my brevity and some lack of trimming; I'm on a smartphone and in a rush.<span></span></div><div><br></div><div>- Chris</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

      lock_name = attr_name + '_lock'<br>
      def getprop(self):<br>
        with getattr(self, lock_name):<br>
          # innards removed here<br>
          pass<br>
        return getattr(self, attr_name, unset_object)<br>
      return property(getprop)<br>
    return made_file_property<br>
<br>
  @file_property<br>
  def f(self, foo=1):<br>
    print "foo=%r" % (foo,)<br>
<br>
  @make_file_property(attr_name="_blah")<br>
  def f2(self, foo=2):<br>
    print "foo=%r" % (foo,)<br>
<br>
Can someone explain what I'm doing wrong, or tell me this is a python<br>
bug?<br>
--<br>
Cameron Simpson <<a href="javascript:;" onclick="_e(event, 'cvml', 'cs@zip.com.au')">cs@zip.com.au</a>><br>
<br>
Bolts get me through times of no courage better than courage gets me<br>
through times of no bolts!<br>
        - Eric Hirst <<a href="javascript:;" onclick="_e(event, 'cvml', 'eric@u.washington.edu')">eric@u.washington.edu</a>><br>
--<br>
<a href="http://mail.python.org/mailman/listinfo/python-list" target="_blank">http://mail.python.org/mailman/listinfo/python-list</a><br>
</blockquote><br><br>-- <br>Cheers,<br>Chris<br>--<br><a href="http://rebertia.com" target="_blank">http://rebertia.com</a><br>