classification
Title: Cannot declare multiple classes via exec when inside a function.
Type: Stage:
Components: Versions: Python 2.5
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: amaury.forgeotdarc, kfitch
Priority: normal Keywords:

Created on 2008-11-21 20:33 by kfitch, last changed 2008-11-21 21:53 by amaury.forgeotdarc. This issue is now closed.

Messages (2)
msg76202 - (view) Author: Kevin Fitch (kfitch) Date: 2008-11-21 20:33
codeText = """
class foo(object): pass
class bar(object):
  baz = foo()
"""

def doExec(text):
  exec text

### This works:
# Although if I do this before the doExec below, then the
# doExec doesn't fail.
# exec codeText

### But this does not:
doExec(codeText)


The output I get is:
---------------------------------------------------------------------------
<type 'exceptions.NameError'>             Traceback (most recent call last)

/home/kfitch/<ipython console> in <module>()

/home/kfitch/<ipython console> in doExec(text)

/home/kfitch/<string> in <module>()

/home/kfitch/<string> in bar()

<type 'exceptions.NameError'>: name 'foo' is not defined



I don't fully understand why the version in the function doesn't work,
but I suspect it is a bug related to scoping, since foo is really
doExec.foo (I think).

This is with python 2.5.2 under Linux (Ubuntu 8.04)
msg76205 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-11-21 21:53
I agree that it is confusing; in short: a bare exec() does not play well with closures;  
This is a consequence of the python execution model, and is unlikely to change.

Here, the class 'foo' is stored in the function's local variables.
But the execution of the body of the 'bar' class searches names in its local scope (the 
class body) and the global scope (the module level), and misses the function's 
locals...

I strongly suggest to avoid pure exec() statements; always specify a global and/or a 
local dictionary.

In your case, the following works:

def doExec(text):
  d = {}  # or:   d = dict(globals())
  exec text in d
  print d.keys()
History
Date User Action Args
2008-11-21 21:53:43amaury.forgeotdarcsetstatus: open -> closed
resolution: wont fix
messages: + msg76205
nosy: + amaury.forgeotdarc
2008-11-21 20:33:45kfitchcreate