A dict comprehension is executed in a new scope, like a function.
As such, the expression locals are limited to just those named in the loop, in this case arg
. The parent function locals are not considered, because closures are only bound at compile time. Names referenced by eval()
cannot make use of closures.
The following also doesn't work:
>>> 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
The names a
and b
are not available to the inner foo
function unless the compiler has determined that that function actually needs access to them:
>>> 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')
Here, the line a, b
can only be referring to the parent scope locals (they are not assigned to in foo()
itself), so the compiler has created closures for these and the names have become available as locals within foo()
.
List comprehensions in Python 2 do not have their own namespace, an omission corrected in Python 3 and not extended to dict and set comprehensions. See Python list comprehension rebind names even after scope of comprehension. Is this right?