这个问题已经在这里有了答案:




8年前关闭。






我以前使用过装饰器,所以我很惊讶地发现我的代码中有一个错误:

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
"""

我的解决方法是在第一次使用后将 panel 更改为 panel2:
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})

现在一切正常,我想知道为什么。

这就是我猜发生的事情,但我不知道:

面板 = zip(..)

意味着面板是一个局部变量。这意味着该函数不会在面板的外部范围内查找。

这是在 get() 函数运行之前完成的,而不是中途完成的?

我认为它会首先从外部函数中获取面板,然后当面板在内部函数中定义时,它会从那时起使用新的本地面板变量。

我在正确的轨道上吗?

最佳答案

是的。

Python 的作用域规则表明一个函数定义了一个新的作用域级别,并且一个名称仅绑定(bind)到一个作用域级别中一个作用域级别中的值——它是静态作用域的(即所有作用域都在编译时确定)。正如您所理解的,您试图通过读取非局部声明并写入局部变量来违反这一点。正如您所观察到的,解释器通过提高 UnboundLocalError 强烈反对这一点:它已经理解 panels 是一个局部变量(因为它不能同时是那个和非局部变量),但您还没有分配(绑定(bind)) 名称的值,因此失败。

更多技术细节

决定是在 Python 中做出的,以跟踪编译时字节码中变量的位置(对于这种情况,它位于局部变量的元组 get.__code__.co_varnames 中),这意味着变量只能在单个范围级别中使用在一定范围内。在 Python 2.x 中,不能修改非局部变量;您可以使用 global 语句对全局变量或非局部变量进行只读访问,或者对全局变量进行读写访问,或者对局部变量进行读写访问(默认)。这就是它的设计方式(可能是为了性能和纯度)。在 Python 3 中,引入了 nonlocal 语句,其效果与 global 类似,但用于中间范围。

在这种情况下,将修改后的变量绑定(bind)到不同的名称是正确的解决方案。

10-07 19:11
查看更多