Issue 31401: Dynamic compilation that uses function in comprehension fails when compiled inside function (original) (raw)
Execution fails with NameError when trying to dynamically compile a Python program that uses a function in a comprehension, and the code is compiled inside a function call, rather than as a global statement.
Using the attached files to reproduce (in reproduce.zip):
python3 compile_in_function.py comprehension.py #fails python3 compile_global.py comprehension.py # works python2 compile_in_function.py comprehension.py #works with Python 2.7.12
Woops, sorry about that, makes sense. Below an example (same idea as the files):
Python 3.6.2 (default, Sep 9 2017, 13:27:06)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> src = """
... def f(x): return x
... [f(v) for v in [1,2,3]]
... """
>>> def comp():
... exec(compile(src, filename='<str>', mode='exec'))
...
>>> comp()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in comp
File "<str>", line 3, in <module>
File "<str>", line 3, in <listcomp>
NameError: name 'f' is not defined
>>> exec(compile(src, filename='<str>', mode='exec'))
>>>
List comprehension is irrelevant here, any nested function has the same problem. And the inner name doesn't have to refer to a function. Also, compilation as a separate step is not necessary.
So the minimal example is
src = '''\
a = 5
def g(x): return a + x
print(g(3))
'''
def comp(): exec(src)
comp()
But I'm not sure if it is a bug at all. If you write explicitly
exec(src, {})
you get a result 8 without problem. The docs say
...if the optional parts are omitted, the code is executed in the current scope.
And the current scope inside comp is "fast locals", where you can't really make new names. Maybe exec should raise an exception then, but it surely cannot just "work" inside fast locals scope.