This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: exec scoping problem
Type: Stage:
Components: Interpreter Core Versions: Python 2.3
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: arigo, kquick
Priority: normal Keywords:

Created on 2004-12-22 19:27 by kquick, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
execprob.py kquick, 2004-12-22 19:27 execprob.py
submod.py kquick, 2004-12-22 19:27 submod.py
Messages (2)
msg23812 - (view) Author: Kevin Quick (kquick) Date: 2004-12-22 19:27
Python 2.3.3 (#1, Oct 18 2004, 16:10:24) 
[GCC 3.3.4 20040623 (Gentoo Linux 3.3.4-r1, ssp-3.3.2-2, pie-8.7.6)] 
on linux2

Using exec on a code object with an "in ..." statement to specify locals 
and globals does not appear to set the globals for any code objects 
called by the exec'd code object.

As a workaround, I can exec a file object containing the relevant code 
objects and the scope appears to work, although the following issues are 
noted (these are possibly separate bugs, but all demonstrated by the 
attached... let me know if you'd like separate bugreport submissions, but 
I figured it was easiest to start with one in case I'm way off base in some 
fundamental way).

1. exec won't process an opened .pyc file, only a .py file.  However, the 
module's __file__ attribute will specify the .pyc or the .py, depending 
on which one is more recent.  This forces me to reset the extension to 
.py at all times.  It also means that if I use this technique I must ensure 
that the .py is always available relative to the .pyc.

2. The exec'd file needs the addition of a "if __name__ == '__main__'" 
to invoke the functionality I want.  This makes sense for exec'ing a 
file, but because I'm forced to exec the file to get globals scoped as I 
wanted, rather than using the code object, I am then limited to that 
single function invocation for any __name__ == "__main__" 
invocation of the file.

3. Specifying "in locals()" for the code object invocation has no 
adverse (or positive) effect, but specifying it for the file object seems 
to cause the interpreter to recurse the *current* file, not the exec'd file 
(this is Test #5 in the attachment).
msg23813 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2004-12-23 22:35
Logged In: YES 
user_id=4771

This is actually all expected behavior, although the test 5 
suprised me much at first, because there should be no 
difference at all between test 4 and test 5: the "in locals()" 
has no effect.  In fact, there is no difference.  You can add or 
remove "in locals()" in both tests 4 and 5 and it's always test 5 
(i.e. the second time the same test) that fails.  The reason is 
a bit subtle.

Specifying a globals in exec is "not recursive", so to say, 
because every function call executes the callee in the globals 
where it was originally defined.  These globals are attached to 
the function object (but not to the code object).  So tests 2 
and 3 (which are exactly equivalent) strip naked the code of 
greet and run it into a globals where it was not expected to 
be; it's as if you took the source code of the function and 
pasted it in place of the exec.  It finds globalvar in the current 
module, and it also finds show_globalvar() because you 
imported it in the line "from submod import *", but this calls 
the unmodified show_globalvar() in submod.py, hence the 
NameError.

If you wanted so-called recursive custom globals, all functions 
calls would have to be replaced by exec's.  I assume you know 
that using classes and instances looks like a much cleaner 
solution...

Now test 4 passes because it's as if you had pasted the whole 
source code of submod.py there.  In particular, you are 
creating a new version of all the functions, which live in the 
execprob module.  Now when test 5 runs, the expression 
'greet.__module__' has a new meaning: 'greet' is now the 
name of the function defined in the current module by the test 
4... so now 'greet.__module__' actually names the current 
module, and you're executing the current module recursively.
History
Date User Action Args
2022-04-11 14:56:08adminsetgithub: 41361
2004-12-22 19:27:19kquickcreate