exec throws an exception...why?

Hung Jung Lu hungjunglu at yahoo.com
Sun Jun 6 17:18:57 CEST 2004


nicksjacobson at yahoo.com (Nick Jacobson) wrote:
> > Now, why it puts 'x' in local, I don't know. 
> 
> I don't know either, that's why I asked ;)

The name binding in assignment seems to proceed only for locals,
unless a variable is declared as global explicitly. That is, by
default, the supplied global dictionary is read-only, unless the
'global' statment is used explicitly for those variables that you want
to override. Think of this behavior as if the code defined in the s
string were executed inside another nameless function.

#--------------- try this first in console
s='''
x = 1
def f():
    print 'globals', globals().keys()
    print 'locals', locals().keys()
    print x
print 'globals', globals().keys()
print 'locals', locals().keys()
f()
'''
d={}
e={}
a = compile(s, '<string>', 'exec')
exec a in d, e
#--------------- output
globals ['__builtins__']
locals ['x', 'f']
globals ['__builtins__']
locals []
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<string>", line 9, in ?
  File "<string>", line 6, in f
NameError: global name 'x' is not defined

#--------------- now try this in console
s='''
global x
x = 1
def f():
    print 'globals', globals().keys()
    print 'locals', locals().keys()
    print x
print 'globals', globals().keys()
print 'locals', locals().keys()
f()
'''
d={}
e={}
a = compile(s, '<string>', 'exec')
exec a in d, e
#--------------- output
globals ['__builtins__', 'x']
locals ['f']
globals ['__builtins__', 'x']
locals []

#--------------- also try this from fresh console
s='''
x = 1
def f():
    print 'globals', globals().keys()
    print 'locals', locals().keys()
    print x
print 'globals', globals().keys()
print 'locals', locals().keys()
f()
'''
a = compile(s, '<string>', 'exec')
exec a
#--------------- output
globals ['a', 's', 'x', '__builtins__', '__name__', 'f', '__doc__']
locals ['a', 's', 'x', '__builtins__', '__name__', 'f', '__doc__']
globals ['a', 's', 'x', '__builtins__', '__name__', 'f', '__doc__']
locals []
1

-------------------------------------------
Therefore, when no dictionary is supplied, it works because it uses
the current globals() and locals() of the current scope, which in the
case of console or module level (i.e., zero indentation) are referring
to the same dictionary. The assignment 'x=1' was performed on the
locals() dictionary for writing. But inside the f() function, the
statement 'print x' pulls the value from the globals() dictionary.
This coincidence of two dictionaries only happens when you run the
code from the module level. If you put the above code inside a
function, it won't work.

#--------------- from a fresh console
def test():
    s='''
x = 1
def f():
    print 'globals', globals().keys()
    print 'locals', locals().keys()
    print x
print 'globals', globals().keys()
print 'locals', locals().keys()
f()
'''
    a = compile(s, '<string>', 'exec')
    exec a

test()
#--------------- output
globals ['__builtins__', '__name__', 'test', '__doc__']
locals ['a', 'x', 's', 'f']
globals ['__builtins__', '__name__', 'test', '__doc__']
locals []
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 14, in test
  File "<string>", line 9, in ?
  File "<string>", line 6, in f
NameError: global name 'x' is not defined

regards,

Hung Jung



More information about the Python-list mailing list