在使用相同名称定义局部变量之前,python无法访问非局部变量

rob*_*ing 7 python scope decorator

可能重复:
Python嵌套函数变量作用域

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

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
"""
Run Code Online (Sandbox Code Playgroud)

我的解决方法是改变panelpanel2超出第一种用法:

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})
Run Code Online (Sandbox Code Playgroud)

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

这就是我想的事情,但我不知道:

panels = zip(..)

表示面板是局部变量.这意味着该功能不会在面板的外观中查看.

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

我认为首先从外部函数中获取面板,然后在内部函数中定义面板之后,从那时起它将使用新的局部面板变量.

我是在正确的轨道上吗?

wim*_*wim 5

您或多或少是正确的,并且找到了正确的分辨率。您的问题等效于此:

bars = range(10)

def foo():
  thing = [x for x in bars]
  bars = 'hello'

foo()
# UnboundLocalError: local variable 'bars' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

基本上在函数定义时,决定bars是局部作用域。然后在函数运行时,您会遇到尚未分配小节的问题。


Chr*_*gan 5

是.

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

更多技术细节

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

在这种情况下,将修改后的变量绑定到其他名称是正确的解决方案.