[Python-Dev] effect of "exec" on local scope

Terry Reedy tjreedy at udel.edu
Wed Oct 8 21:17:06 CEST 2008


Willem Broekema wrote:
> The issue came up while trying to get some Sympy code running on CLPython.
> 
> class C:
>  exec "a = 3"
>  print locals()
> 
> 1. Is it guaranteed that class C gets an attribute "a", i.e. that the
> locals printed include {'a': 3}?
> 2. It it (also) guaranteed if it were in a function scope?
> 
> The complete syntax of exec is:
>  exec CODE in Y, Z
> where Y, Z are optional.
> 
> The documentation of "exec" says "if the optional parts are
> omitted,the code is executed in the current scope." There are at least
> two different interpretations:
> 
>  a. The code is executed in the current class scope, so the assignment
> must have an effect on the class scope.
> 
>  b. The scope defaults to the local scope, by which is meant the
> mapping returned by locals(), and of locals() the documentation says
> that changes made to it may not influence the interpreter. (The
> documentation of exec suggests using globals() and locals() as
> arguments to exec, which seems hint at this interpretation.)
> 
> The relevant documentation:
>  exec: http://docs.python.org/reference/simple_stmts.html#grammar-token-exec_stmt
>  locals: http://docs.python.org/library/functions.html#locals

The 3.0 doc for exec() has this warning:
"Warning
The default locals act as described for function locals() below: 
modifications to the default locals dictionary should not be attempted. 
Pass an explicit locals dictionary if you need to see effects of the 
code on locals after function exec() returns."

This implies interpretation b.

However, is spite of the warning, class locals is a dict and locals() is 
that dict, so a is available for further use in class code.

So the answer to question 1 for current CPython is yes.

Whether that is guaranteed for all implementations and versions is 
another story.

Functions are much trickier.  The local namespace is not a dict, and 
modifying the locals() dict does not modify the namespace.  The answer 
to 2. is No, not even now.

 >>> def f():
	exec('a=3')
	print(locals())
	return a

 >>> f()
{'a': 3}
Traceback (most recent call last):
   File "<pyshell#37>", line 1, in <module>
     f()
   File "<pyshell#36>", line 4, in f
     return a
NameError: global name 'a' is not defined

But why then is 'a' printed in the second call to locals (the implied 
one in exec being the first)?  It appears that a function or code object 
can have only only one repeatedly used shadow dict.  The 3.0 (and 2.5) 
doc says "locals()
Update and return a dictionary representing the current local symbol 
table."  Note "update"; I had missed that before.  To see this...

 >>> def g():
	a =  locals()
	b = locals()
	return id(a), id(b), a,b

 >>> g()
(20622048, 20622048, {'a': {...}}, {'a': {...}})

Inserting "print(a['a'])" between the locals calls raises KeyError.

Terry Jan Reedy




More information about the Python-Dev mailing list