在下面的代码中,对iszero
的第一次引用成功,但第二次引用(在lambda中)给出了NameError: 'iszero' is not defined
。
myblock = """
def iszero(x):
return x == 0
print(iszero(0)) #works
args = [0, 1, 2]
flts = list(filter(lambda f:(not iszero(f)), args)) #NameError
"""
mylocals = {}
exec(myblock, globals(), mylocals)
答案 0 :(得分:2)
我将其归类为Python错误(至少是文档错误)。
中打开一个问题问题与lambda
无关,看起来像提供locals
词典时由exec创建的闭包没有正确的范围解析。
奇怪的是,PyPy具有相同的行为,因此可能这确实是预期的结果(但我无法理解它在哪里记录)。
这可能看起来很奇怪,但这是预期的行为。
原因是当exec
同时提供了global
和local
字典时,代码就会被执行,就像它在类定义的主体中一样
该上下文非常具体,并且在其中创建的闭包不能访问在类的范围内定义的名称(这就是为什么需要在方法中使用myclass.myattribute
来访问类属性 - 这是一个从全局开始的查找)。
这种奇怪的行为并不经常发生,因为通常类定义范围内的代码只对简单的赋值(对于类级属性)和定义(对于方法)不会尝试捕获这些名称。
答案 1 :(得分:0)
我在此理解的是,exec(myblock)
这始终是向locals()
添加实体。我确实验证了以下情况..
当您使用locals
时,这就是python管理globals
和exec
的方式。
if (globals == Py_None) {
globals = PyEval_GetGlobals();
if (locals == Py_None) {
locals = PyEval_GetLocals();
if (locals == NULL)
return NULL;
}
if (!globals || !locals) {
PyErr_SetString(PyExc_SystemError,
"globals and locals cannot be NULL");
return NULL;
}
}
else if (locals == Py_None)
locals = globals;
按照上面的逻辑,当你执行exec(myblock, None, None)
时,python获取globals()
并且与上述逻辑的exec(myblock, globals(), globals())
表达式相同。以下是我们同时提供locals() is globals()
时验证是否为None
的简单表达式。
>>> exec("print(locals() is globals())", None, None)
True
同样地,当我们提供locals
作为None
时,根据上面的python逻辑if (locals == Py_None) locals = globals
,两者都会引用相同的对象,即globals
。< / p>
>>> exec("print(locals() is globals())", globals(), None)
True
当我们将locals
作为空dict {}
传递时,根据上述逻辑,它不会对局部变量进行任何类型的更改。
>>> exec("print(locals() is globals())", globals(), {})
False
现在让我们看看你的案子中发生了什么......
我已经修改了你的脚本并添加了print(list(globals()), list(locals())); print(locals() is globals())
这两行,如下所示。
myblock = """
def iszero(x):
return x == 0
args = [0, 1, 2]
# added these two stmts here
print(list(locals()))
print(list(globals()))
print(locals() is globals())
flts = list(filter(lambda f:(not iszero(f)), args)) #NameError
"""
使用exec
locals
作为空字典执行上述字符串后。
>>> exec(myblock, globals(), {})
['iszero', 'args']
['__package__', 'myblock', '__builtins__', '__spec__', '__doc__', '__loader__', '__name__']
False
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 12, in <module>
File "<string>", line 12, in <lambda>
NameError: name 'iszero' is not defined
很明显,locals
空间会添加所有属性。因此,如果您将iszero
作为globals
传递,则永远不会在locals
中看到{}
方法。
您收到NameError
list(filter(lambda f:(not iszero(f)), args))
的原因是它开始在globals
而不是locals
进行查找,并且您的全局变量没有定义方法。< / p>