[Python-Dev] Python3 compiled listcomp can't see local var - bug or feature?

Nick Coghlan ncoghlan at gmail.com
Wed Jun 6 09:51:55 EDT 2018

On 6 June 2018 at 15:31, Rob Cliffe via Python-Dev <python-dev at python.org>

> Is this a bug or a feature?
> Consider the following program:
> # TestProgram.py
> def Test():
>   # global x
>     x = 1
>     exec(compile('print([x+1,x+2])', 'MyTest', 'exec'))
>     exec(compile('print([x+i for i in range(1,3)])', 'MyTest', 'exec'))
> Test()
> In Python 2.7.15 the output is
> [2, 3]
> [2, 3]
> In Python 3.6.5 the output is
> [2, 3]
> Traceback (most recent call last):
>   File "TestProgram.py", line 7, in <module>
>     Test()
>   File "TestProgram.py", line 6, in Test
>     exec(compile('print([x+i for i in range(1,3)])', 'MyTest', 'exec'))
>   File "MyTest", line 1, in <module>
>   File "MyTest", line 1, in <listcomp>
> NameError: name 'x' is not defined
> If the "global x" declaration is uncommented, this "fixes" the Python
> 3.6.5 behaviour,
> i.e. no error occurs and the output is the same as for Python 2.7.15.
> *In other words, it looks as if in Python 3.6.5, the compiled list
> comprehension*
> *can "see" a pre-existing global variable but not a local one.*
Yes, this is expected behaviour - the two-namespace form of exec (which is
what you get implicitly when you use it inside a function body) is similar
to a class body, and hence nested functions (including the implicit ones
created for comprehensions) can't see the top level local variables.

You can override that and force the use of the single-namespace form by
passing the locals() namespace into exec() explicitly:

    def explicit_local_namespace():
        x = 1
        exec(compile('print([x+i for i in range(1,3)])', 'MyTest', 'exec'),

(Note: you'll then need to use collections.ChainMap instead of separate
locals and globals namespaces if you want the exec'ed code to still be able
to see the module globals in addition to the function locals)


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180606/45723401/attachment.html>

More information about the Python-Dev mailing list