4

为什么eval在字典理解中访问函数参数会失败?

ARGS1 = ('a1', 'b1')
def foo1(a1, b1):
    return {arg:eval(arg) for arg in ARGS1}
print foo1("A1", "B1") # NameError: name 'a1' is not defined

列表理解中的相同内容很好:

ARGS2 = ('a2', 'b2')
def foo2(a2, b2):
    return [eval(arg) for arg in ARGS2]
print foo2("A2", "B2") # OK, print: ['A2', 'B2']

没有功能它也能很好地工作:

ARGS3 = ('a3', 'b3')
a3, b3 = ("A3", "B3")
print {arg:eval(arg) for arg in ARGS3} # OK, print: ['A3', 'B3']

或者如果定义了全局变量:

ARGS4 = ('a4', 'b4')
a4, b4 = ("A4", "B4")
def foo4():
    return [eval(arg) for arg in ARGS4]
print foo4() # OK, print: ['A4', 'B4']

这真的看起来像一个错误,但也许我在这里遗漏了一些东西。

(已编辑以包括无功能和有全局示例)

4

1 回答 1

5

dict 理解在新范围内执行,就像函数一样。

因此,表达式 locals 仅限于循环中命名的那些,在这种情况下是arg. 考虑父函数局部变量,因为闭包在编译时绑定。引用的名称eval()不能使用闭包。

以下不起作用:

>>> ARGS = ('a', 'b')
>>> def bar(a, b):
...     def foo():
...         for arg in ARGS:
...             eval(arg)
...     return foo
... 
>>> print bar("A", "B")()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in foo
  File "<string>", line 1, in <module>
NameError: name 'a' is not defined

名称ab对内部函数不可用,foo除非编译器确定该函数实际上需要访问它们:

>>> def bar2(a, b):
...     def foo():
...         a, b
...         for arg in ARGS:
...             eval(arg)
...     return foo
... 
>>> print bar2("A", "B")()
None
>>> print bar2("A", "B").func_closure
(<cell at 0x1051bac20: str object at 0x104613328>, <cell at 0x1051bacc8: str object at 0x1045971e8>)
>>> print bar2("A", "B").__code__.co_freevars
('a', 'b')

这里,该行a, b只能引用父作用域 locals(它们foo()本身并未分配给它们),因此编译器为它们创建了闭包,并且名称已成为. foo()

Python 2 中的列表推导没有自己的命名空间,在 Python 3 中更正了一个遗漏,并且没有扩展到 dict 和 set 推导。即使在理解范围之后,请参阅Python 列表理解重新绑定名称。这是正确的吗?

于 2013-09-06T18:36:15.440 回答