Exec woes
Hendrik van Rooyen
mail at microcorp.co.za
Wed Jan 28 02:47:00 EST 2009
Stephen Hansen wrote:
>Hendrik van Rooyen wrote:
>>IDLE 1.1.3 ==== No Subprocess ====
>>>>> help(exec)
>>SyntaxError: invalid syntax
>>>>>
>>Its the same under Linux SuSe, Python 2.5.1.
>>
>>I think this is a BUG.
>
>Exec is a statement, not a function nor an object: even though you can enclose
parens around its arguments like you do later on, they >don't have any syntax
meaning
This is actually not correct - it is the root cause of my trouble.
if you write, in a nested scope:
exec ( "somestring to execute" in globals(),locals())
You get the syntax error, as the interpreter somehow sees it as one, unqualified
thing.
I did this, and it did not work in my real code, and that is why I started
putting
together the little example - all the trouble caused by too many parenthesis.
But it is a GoodThing I made the error, because it has taught me more about
how the scopes work.
>
>You can't help(print) or help(import) either.
Right - was not aware of this - I suppose it has never occured to me
to ask for help on print or import.
>>Anyway, my real problem looks like this:
>>>>> def Somefunc():
>> def excrescence():
>> exec('BUILD = "someString"')
>> return BUILD
>>
>>SyntaxError: unqualified exec is not allowed in function 'excrescence
>>it is a nested function (<pyshell#11>, line 3)
>>>>>
>>
>>Now this works if it is not nested, and it works if it is a method in a class.
>>Why the complaint about the nestedness?
>>
>>
>Once upon a time, Python had only two scopes or namespaces: local and globals.
It'd look up variables in the local scope and if it didn't >find them, it'd look
them up in the global scope. (There's also the builtin namespace but to not
digress...)
8<----------------------- historic position ----------------
>
>Then PEP227 came around to add nested scopes -- or lexical scopes. Its what
made "nested" functions like that actually useful: it's what >brought closures
into the scenario. As of Python 2.2, within bar() it would be able to see the
definition of a because namespaces can >now be nested.
>
>This addition was a problem for a couple features: doing "from blah import *"
within a function, and a bare exec (an exec without an >explicit globals() and
locals()) that happened in certain places-- in this case a nested function. They
introduced that SyntaxError to make >sure it wouldn't accidentally hit you. Read
up on PEP227 for the full details.
>
Thanks - will do, but I think I am already getting the picture.
>To get around this, you need to specify exactly what scope you want exec to
happen in when you're in a place where the 'current' scope >is nested. You
qualify exec--
>
Right - and it also works if you simply use the current locals() in the global
position.
I suppose one should use the scope "one up" in globals, and locals() as locals,
but I can't figure out how to do that directly. (I mean using Somefunc'c
locals() as the
global for the exec, and excrescence's locals() as the locals - would require
keeping
a reference - see below)
>
>>So there is some namespace thing happening that is too subtle for me, and I
>>would like to know what "unqualified" means in the above message, and
>>what one must do to "qualify" the statement, if that is what is needed.
>>
>
>by doing:
>
> exec code in <global dictionary>, <local dictionary>
>
>In your situation:
>
> >>> def Somefunc():
> def excrescence():
> exec "BUILD = 'someString'" in globals(), locals()
>
>is probably sufficient. globals() returns the dictionary of the global
namespace, locals() the dictionary of the current functions (non->nested)
namespace.
>
This works, thank you. However, locals() give you the nested function's
namespace.
The following illustrates what is going on:
>>> def Somefunc():
print 'in Somefunc:',locals,id(locals),id(locals())
def excrescence():
print 'in excrescence:',locals,id(locals),id(locals())
exec "BUILD = 'someString'" in locals()
print 'in excrescence:',locals,id(locals),id(locals())
return BUILD
foo = excrescence()
print 'in Somefunc:',locals,id(locals),id(locals())
return foo
>>> Somefunc()
in Somefunc: <built-in function locals> 7599848 18705696
in excrescence: <built-in function locals> 7599848 18799040
in excrescence: <built-in function locals> 7599848 18799040
in Somefunc: <built-in function locals> 7599848 18705696
'someString'
>>>
This leads me to speculate into other evil ways - if I use the outer locals,
I need not even return the thing, it would get defined:
>>> def Somefunc():
print 'in Somefunc:',locals,id(locals),id(locals())
outer_locals = locals()
def excrescence():
print 'in excrescence:',locals,id(locals),id(locals())
exec "BUILD = 'someString'" in outer_locals
print 'in excrescence:',locals,id(locals),id(locals())
return None
foo = excrescence()
print 'in Somefunc:',locals,id(locals),id(locals())
return BUILD
>>> Somefunc()
in Somefunc: <built-in function locals> 7599848 18822032
in excrescence: <built-in function locals> 7599848 18619824
in excrescence: <built-in function locals> 7599848 18619824
in Somefunc: <built-in function locals> 7599848 18822032
'someString'
>>>
And so it does.
Using the locals like this in the globals position is not a good idea,
except for purposes of illustration, like here - if one actually prints the
contents of the dict after the exec, you see what is meant by namespace
pollution....
Thank you to all who have responded - I think I have it now
- Hendrik
More information about the Python-list
mailing list