exec中具有空本地变量的列表理解:NameError [英] list comprehension in exec with empty locals: NameError

查看:97
本文介绍了exec中具有空本地变量的列表理解:NameError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下代码段:

def bar():
    return 1
print([bar() for _ in range(5)])

它给出了预期的输出[1, 1, 1, 1, 1].

但是,如果我尝试在空环境中(localsglobals都设置为{})中的exec相同代码段,则会给出NameError:

However, if I try to exec the same snippet in empty environment (locals and globals both are set to {}), it gives NameError:

if 'bar' in globals() or 'bar' in locals():
    del bar
# make sure we reset settings

exec("""
def bar():
    return 1
print([bar() for _ in range(5)])
""", {}, {})

NameError: name 'bar' is not defined

如果我像exec(…, {})exec(…)那样调用exec,则会按预期执行.

If I invoke exec like exec(…, {}) or exec(…), it is executed as expected.

为什么?

还请考虑以下代码段:

def foo():
    def bar():
        return 1
    print('bar' in globals()) # False
    print('bar' in locals()) # True
    print(['bar' in locals() for _ in [1]]) # [False]
    print([bar() for _ in [1, 2]]) # [1, 1]

就像我的第一位高管一样,列表理解内的本地人没有酒吧.但是,如果我们尝试调用它,它将起作用!

Just like in my first exec, we don't have bar in locals inside list comprehension. However, if we try to invoke it, it works!

推荐答案

解决问题的方法就在这里:

The solution to your problem lies here:

在所有情况下,如果省略了可选部分,则代码将在当前作用域中执行. 如果仅提供全局变量,则必须为字典,该字典将用于全局变量和局部变量.如果指定了globals和locals,则它们分别用于全局变量和local变量.如果提供,locals可以是任何映射对象. 请记住,在模块级别,全局变量和局部变量是同一本字典.如果exec作为全局变量和局部变量获得两个单独的对象,则代码将像嵌入在类定义中一样被执行.

In all cases, if the optional parts are omitted, the code is executed in the current scope. If only globals is provided, it must be a dictionary, which will be used for both the global and the local variables. If globals and locals are given, they are used for the global and local variables, respectively. If provided, locals can be any mapping object. Remember that at module level, globals and locals are the same dictionary. If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.

https://docs.python.org/3/library/functions. html#exec

基本上,您的问题是bar在locals的范围内定义,并且仅在locals中定义.因此,此exec()语句有效:

Basically, your problem is that bar is defined in the scope of locals and only in locals. Therefore, this exec() statement works:

exec("""
def bar():
    return 1
print(bar())
""", {}, {})

但是列表理解会创建一个新的本地范围,其中未定义bar,因此无法对其进行查找.

The list comprehension however creates a new local scope, one in which bar is not defined and can therefore not be looked up.

可以用以下方式说明此行为:

This behaviour can be illustrated with:

exec("""
def bar():
    return 1
print(bar())
print(locals())
print([locals() for _ in range(1)])
""", {}, {})

返回

1
{'bar': <function bar at 0x108efde18>}
[{'_': 0, '.0': <range_iterator object at 0x108fa8780>}]

编辑

在您的原始示例中,bar的定义在(模块级别)全局范围中找到.这对应于

In your original example, the definition of bar is found in the (module level) global scope. This corresponds to

请记住,在模块级别,全局变量和局部变量是相同的字典.

Remember that at module level, globals and locals are the same dictionary.

exec示例中,您通过传递两个不同的字典在全局变量和局部变量之间引入了一个人为的划分.如果您传递相同的一个或仅传递一个全局变量(这反过来意味着该变量将同时用于globalslocals),则您的示例也将起作用.

In the exec example, you introduce an artificial split in scopes between globals and locals by passing two different dictionaries. If you passed the same one or only the globals one (which would in turn mean that this one will be used for both globals and locals) , your example would also work.

对于在编辑中引入的示例,这归结为python中的作用域规则.有关详细说明,请阅读: https://docs .python.org/3/tutorial/classes.html#python-scopes-and-namespaces

As for the example introduced in the edit, this boils down to the scoping rules in python. For a detailed explanation, please read: https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces

简而言之,虽然bar不在列表理解的本地范围内,也不在全局范围内,但它在foo的范围内.根据给定的Python作用域规则,如果在本地范围内找不到变量,则会在封闭范围内搜索该变量,直到达到全局范围为止.在您的示例中,foo的作用域位于本地作用域和全局作用域之间,因此在到达搜索结束之前会找到bar.

In short, while bar is not in the local scope of the list comprehension and neither in the global scope, it is in the scope of foo. And given Python scoping rules, if a variable is not found in the local scope, it will be searched for in the enclosing scopes until the global scope is reached. In your example, foo's scope sits between the local scope and the global scope, so bar will be found before reaching the end of the search.

但是,这仍然与exec示例不同,在exec示例中,您传入的locals范围没有包含列表推导的范围,而是与之完全分开了.

This is however still different to the exec example, where the locals scope you pass in is not enclosing the scope of the list comprehension, but completely divided from it.

关于范围界定规则的另一种很好的解释,包括插图,可以在这里找到: http://sebastianraschka.com/Articles /2014_python_scope_and_namespaces.html

Another great explanation of scoping rules including illustrations can be found here: http://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html

这篇关于exec中具有空本地变量的列表理解:NameError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆