Possible Duplicate:
Python nested functions variable scoping
I've used decorators before and so I was surprised to find a bug in my code:
def make_handler(name, panels):
def get(self):
admin = True
keys = [ndb.Key('Panel', panel) for panel in panels]
panels = zip(ndb.get_multi(keys), panels)
panels = [(panel.panel_html if panel else get_default_content(panel_id), panel_id) for panel, panel_id in panels]
templates = {'panels': panels, 'admin': admin}
self.render_template('panel_page.html', **templates)
return type(name, (BaseHandler,), {'get': get})
"""
Traceback (most recent call last):
File "C:\Program Files\Google\google_appengine\lib\webapp2\webapp2.py", line 1536, in __call__
rv = self.handle_exception(request, response, e)
File "C:\Program Files\Google\google_appengine\lib\webapp2\webapp2.py", line 1530, in __call__
rv = self.router.dispatch(request, response)
File "C:\Program Files\Google\google_appengine\lib\webapp2\webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "C:\Program Files\Google\google_appengine\lib\webapp2\webapp2.py", line 1102, in __call__
return handler.dispatch()
File "C:\Program Files\Google\google_appengine\lib\webapp2\webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "C:\Program Files\Google\google_appengine\lib\webapp2\webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "C:\Users\Robert\PycharmProjects\balmoral_doctors\main.py", line 35, in get
keys = [ndb.Key('Panel', panel) for panel in panels]
UnboundLocalError: local variable 'panels' referenced before assignment
"""
My fix is to change panel to panel2 beyond the first usage:
def make_handler(name, panels):
def get(self):
admin = True
keys = [ndb.Key('Panel', panel) for panel in panels]
panels2 = zip(ndb.get_multi(keys), panels)
panels2 = [(panel.panel_html if panel else get_default_content(panel_id), panel_id) for panel, panel_id in panels2]
templates = {'panels': panels2, 'admin': admin}
self.render_template('panel_page.html', **templates)
return type(name, (BaseHandler,), {'get': get})
Now everything works fine and I'm wondering why.
This is what I guess happens but I don't know:
panels = zip(..)
means that panels is a local variable. That means the function doesn't look in the outerscope for panels.
This is done before the get() function is run, and not midway through?
I thought it would firstly grab panels from the outer function, and then when panels gets defined in the inner function after that, it would from then on use the new local panels variable.
Am I on the right track?