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

> 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'),
locals())
    explicit_local_namespace()

(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)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to