这是一个非常微妙的观点。因此,如果您阅读 documentation for eval,它并没有提到您为全局变量和本地变量提供参数的情况,但我相当肯定它与 for exec 的工作原理相同:
如果exec 获得两个单独的对象作为全局对象和局部对象,则代码将
就像嵌入在类定义中一样执行。
在类定义中,函数无法访问其封闭范围。所以这与错误完全相同:
>>> class Foo:
... value = [1,2,3]
... print([x in value for x in [2,4,6]])
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in Foo
File "<stdin>", line 3, in <listcomp>
NameError: name 'value' is not defined
因为列表推导是通过在底层创建函数对象来工作的。这也是为什么您需要self.some_method 来访问您的类中定义的其他方法的名称的原因。有关以上内容的更多信息,请访问the excellent accepted answer here。
所以和下面的一样:
>>> def foo():
... x = 3
... return eval('(lambda: x + 1)()', globals(), locals())
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
File "<string>", line 1, in <module>
File "<string>", line 1, in <lambda>
NameError: name 'x' is not defined
但是,这很好用:
>>> def foo():
... x = 3
... return eval('x + 1', globals(), locals())
...
>>> foo()
4
因为不涉及(非)封闭函数范围。
最后,以下工作的原因:
>>> def foo():
... values = [1,2,3]
... return eval('[x+2 for x in values]', globals(), locals())
...
>>> foo()
[3, 4, 5]
是因为理解的 left-most for 子句中的迭代不是在理解的函数范围内而是在理解发生的范围内进行评估的(它实际上被传递为一个论点)。您可以在列表理解的反汇编中看到这一点:
>>> import dis
>>> dis.dis('[x+2 for x in values]')
1 0 LOAD_CONST 0 (<code object <listcomp> at 0x7fe28baee3a0, file "<dis>", line 1>)
2 LOAD_CONST 1 ('<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_NAME 0 (values)
8 GET_ITER
10 CALL_FUNCTION 1
12 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x7fe28baee3a0, file "<dis>", line 1>:
1 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 12 (to 18)
6 STORE_FAST 1 (x)
8 LOAD_FAST 1 (x)
10 LOAD_CONST 0 (2)
12 BINARY_ADD
14 LIST_APPEND 2
16 JUMP_ABSOLUTE 4
>> 18 RETURN_VALUE
注意,values 被评估,iter 被调用,结果被传递给函数:
6 LOAD_NAME 0 (values)
8 GET_ITER
10 CALL_FUNCTION 1
“函数”基本上只是一个带有追加的循环,请参阅:Disassembly of <code object <listcomp> at 0x7fe28baee3a0, file "<dis>", line 1> 了解列表推导如何工作。