Consider the following snippet:
def bar():
return 1
print([bar() for _ in range(5)])
It gives an expected output [1, 1, 1, 1, 1]<
As Hendrik Makait found out, the exec documentation says that
If
execgets two separate objects asglobalsandlocals, the code will be executed as if it were embedded in a class definition.
You can get the same behaviour by embedding the code into a class definition:
class Foo:
def bar():
return 1
print([bar() for _ in range(5)])
Run it in Python 3 and you will get
Traceback (most recent call last):
File "foo.py", line 9, in
class Foo:
File "foo.py", line 15, in Foo
print({bar() for _ in range(5)})
File "foo.py", line 15, in
print({bar() for _ in range(5)})
NameError: global name 'bar' is not defined
The reason for the error is as Hendrik said that a new implicit local scope is created for list comprehensions. However Python only ever looks names up in 2 scopes: global or local. Since neither the global nor the new local scope contains the name bar, you get the NameError.
The code works in Python 2, because list comprehensions have a bug in Python 2 in that they do not create a new scope, and thus they leak variables into their current local scope:
class Foo:
[1 for a in range(5)]
print(locals()['a'])
Run it in Python 2 and the output is 4. The variable a is now within the locals in the class body, and retains the value from the last iteration. In Python 3 you will get a KeyError.
You can get the same error in Python 2 too though, if you use a generator expression, or a dictionary/set comprehension:
class Foo:
def bar():
return 1
print({bar() for _ in range(5)})
The error can be produced also by just using simply
class Foo:
bar = 42
class Bar:
print(bar)
This is unlike
def foo():
bar = 42
def baz():
print(bar)
baz()
because upon execution of foo, Python makes baz into a closure, which will access the bar variable via a special bytecode instruction.