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