Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python可以';在使用相同名称定义局部变量之前,不访问非局部变量_Python_Scope_Decorator - Fatal编程技术网

python可以';在使用相同名称定义局部变量之前,不访问非局部变量

python可以';在使用相同名称定义局部变量之前,不访问非局部变量,python,scope,decorator,Python,Scope,Decorator,可能重复: 我以前使用过decorators,因此我惊讶地发现代码中有一个bug: 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

可能重复:

我以前使用过decorators,因此我惊讶地发现代码中有一个bug:

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})
现在一切正常,我想知道为什么

我猜会发生这种情况,但我不知道:

面板=拉链(…)

表示面板是局部变量。这意味着该功能不会在外部范围内寻找面板

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

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


我在正确的轨道上吗?

如果在函数中分配了变量,则假定该变量引用本地名称,除非您明确声明它是全局的,或者在Python 3.x中是非局部的。如果声明为全局变量,则必须在模块的全局变量中定义该变量,而不包括上述情况。您已经找到了一个Python2.x解决方案;另一种方法是添加
面板
作为
get
的参数,并使用
functools。部分

def make_handler(name, panels):
    def get(self, panels):
        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': functools.partial(get, panels=panels)})

另请参见:,

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

bars = range(10)

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

foo()
# UnboundLocalError: local variable 'bars' referenced before assignment
在函数定义时,确定
为局部范围。然后在函数运行时,您会遇到一个问题,即未分配条

是。

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

更多技术细节 在Python中做出的决定是跟踪变量在字节码编译时的位置(具体到本例中,对于局部变量,它位于元组
get.\uuuuuu code\uuuu.co\u varnames
),这意味着变量只能在特定范围内的单个作用域级别中使用。在Python2.x中,不可能修改非局部变量;您可以对全局或非局部变量进行只读访问,也可以使用
global
语句对全局变量进行读写访问,或者对局部变量进行读写访问(默认设置)。这就是它的设计方式(可能是为了性能和纯度)。在Python3中,引入了
非局部
语句,其效果与
全局
类似,只是用于中间作用域


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

许多人没有意识到这一点,但Python实际上是静态范围的。当Python看到从裸名称(即,不是某个对象的属性)读取时,它可以完全通过编译时分析准确地确定该名称读取的位置

如果在函数中指定了名称,则该名称是该函数1中的局部变量,其作用域扩展到整个函数体,甚至在指定前的行上

如果函数中未指定名称,则该名称为非局部变量。Python可以检查任何周围
def
块的静态范围,以查看它是否是其中任何一个块中的局部变量。如果不是,则该名称必须是对模块全局或内置的引用(全局和内置之间的选择是动态解析的,因此您可以使用动态声明的全局来隐藏内置)

我相信这主要是为了提高效率。这意味着,当编译函数的字节码时,可以知道函数的局部变量集,并且可以将局部变量访问转换为简单的索引操作。否则,Python将不得不执行字典查找来访问局部变量,这将更加缓慢

因此,由于您的
get
函数包含一行
panels=…
,因此
panels
get
整个函数体中的局部变量。对
键的赋值在赋值之前在局部变量
面板上循环



1除非该名称声明为
global
nonlocal
,但这仍然是静态已知的。

Python编译器首先扫描函数内的整个代码,以确定局部变量集(作为参数传递或在函数内分配新的val)。这就是为什么在赋值之前不能在函数中使用赋值变量的原因


如果编译器没有这样做,那么就不可能为函数创建闭包。闭包需要引用所有自由变量或非局部变量。如果一个变量对函数的一部分是自由的,而对另一部分是局部的……这是没有意义的:)

“不可能为函数创建一个闭包”:这不是真的。考虑这个替代模型,这是JavaScript引擎中所做的*:只需跟踪堆栈的堆栈,然后,对于每个变量引用,依次查找每个范围中的变量。通常会比较慢,但这是一个折衷方案。(*或者至少过去是这样;我不确定它的真实性有多大——但是你可以引用一个非局部变量,然后它会被一个lo覆盖