[Python-Dev] variable name resolution in exec is incorrect

Terry Reedy tjreedy at udel.edu
Wed May 26 19:40:43 CEST 2010


Mark Dickinson wrote (with interactice prompts removed)

code = """\
y = 3
def f():
   return y
. f()
"""
exec code in {}   # works fine
exec code in {}, {}   # dies with a NameError

Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "<string>", line 4, in <module>
   File "<string>", line 3, in f
NameError: global name 'y' is not defined

I verified that 3.1 (with exec adjusted to be a function) operates the same.

On 5/26/2010 8:51 AM, Nick Coghlan wrote:
 >exec with a single argument = module namespace
 >exec with two arguments = class namespace

I verified in 3.1 that indenting 'code' and prepending 'class C():\n' 
gives the same error and that prepending 'def f():\n' now, with nexted 
function namespaces, does not give an error, although it would have been 
an error before Python 2.2, when there were no nested function namespaces.

On 5/26/2010 10:03 AM, Colin H wrote:
> Thanks for the details on why the observed behaviour occurs - very
> clear. My only query would be why this is considered correct? Why is
> it running as a class namespace, when it is not a class?

You are expecting that it run as a function namespace (with post 2.2 
nesting), when it is not a function. Why is that any better?

> Is there any
> reason why this is not considered a mistake? Slightly concerned that
> this is being considered not a bug because 'it is how it is'.

In original Python, the snippet would have given an error whether you 
thought of it as being in a class or function context, which is how 
anyone who knew Python then would have expected. Consistency is not a bug.

When nested function namespaces were introduced, the behavior of exec 
was left unchanged. Backward compatibility is not a bug.

A change could have been proposed for 3.x, but I do not remember such a 
discussion and expect it would have been rejected. One can get the 
nested function behavior by doing what I did in the test mentioned 
above. One could easily write a nested_exec function to do the wrapping 
automatically.

-----

In http://bugs.python.org/issue8824

I suggest that

"In all cases, if the optional parts are omitted, the code is executed 
in the current scope. If only globals is provided, it must be a 
dictionary, which will be used for both the global and the local 
variables. If globals  and locals are given, they are used for the 
global and local variables, respectively. If provided, locals can be any 
mapping object."

be followed by

"If only globals is provided or if onedict is provided as both globals 
and locals, the code is executed in a new top-level scope. If different 
objects are given as globals and locals, the code is executed as if it 
were in a class statement in a new top-level scope."

to make the behavior clearer.

Terry Jan Reedy



More information about the Python-Dev mailing list