Luc*_*mon 4 python closures arguments dictionary-comprehension
为什么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
Run Code Online (Sandbox Code Playgroud)
列表理解中同样的事情很好:
ARGS2 = ('a2', 'b2')
def foo2(a2, b2):
return [eval(arg) for arg in ARGS2]
print foo2("A2", "B2") # OK, print: ['A2', 'B2']
Run Code Online (Sandbox Code Playgroud)
没有功能它也很好用:
ARGS3 = ('a3', 'b3')
a3, b3 = ("A3", "B3")
print {arg:eval(arg) for arg in ARGS3} # OK, print: ['A3', 'B3']
Run Code Online (Sandbox Code Playgroud)
或者如果定义了全局变量:
ARGS4 = ('a4', 'b4')
a4, b4 = ("A4", "B4")
def foo4():
return [eval(arg) for arg in ARGS4]
print foo4() # OK, print: ['A4', 'B4']
Run Code Online (Sandbox Code Playgroud)
这真的看起来像一个bug,但也许我在这里遗漏了一些东西.
(已编辑包含无功能和全局示例)
字典理解在新范围内执行,如函数.
因此,表达当地人局限于只是那些在循环命名,在这种情况下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
Run Code Online (Sandbox Code Playgroud)
除非编译器确定该函数确实需要访问它们,否则名称a和b内部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')
Run Code Online (Sandbox Code Playgroud)
在这里,线a, b只能引用父范围当地人(他们不是在分配给foo()自己),所以编译器创造了这些关闭和名字已成为可用当地人中 foo().
Python 2中的列表推导没有自己的命名空间,在Python 3中更正了一个省略,并没有扩展到dict和set comprehension.即使在理解范围之后,也请参阅Python列表理解重新绑定名称.这是正确的吗?