A problem with exec statement

Peter Otten __peter__ at web.de
Sat Apr 15 03:59:55 EDT 2006


TPJ wrote:

>> (...) Even allowing for the
>> difficulties you've already experienced, it's nearly always better in
>> practical cases to use assignment to the keys of a dictionary. Then no
>> exec is required, and you have direct control over your own namespace.
> 
> Well... Is this a sugestion, that instead of messing up with the exec
> statements used to modify local namespaces I should use dictionaries?
> 
> Perhaps you're right. In fact, the problem, that I'm trying to solve is
> as follows:
> 
> def funcA():
> 
>   def funcB():
>     ...
>     var1, var2, var3, ..., varN = ( None, ) * N
>     t = ( (regexp1, 'var1'), (regexp2, 'var2'), ..., (regexpN, 'varN')
> )
>     for regexp, var_name in t:
>       match = regexp.match( some_string )
>       if match != None:
>           # now the *magic* exec statement comes...
>         exec var_name + ' = match.groups()[0]' in globals(), locals()
>     return var1, var2, var3, ..., varN
> 
>   ...
>   k1, k2, k3, ..., kN = funcB()

> My problem is more complicated, that the presented example. In general,
> my problem is: how to create a local variable by executing the Python
> code, that isn't known at the moment of writing the program? In another
> words: I have to create a local variable, whose name will be known at
> the runtime, in a nested function.
> 
> Is it possible, or have I to use dictionaries, instead of exec
> statement used to modify local namespaces?

There is a mismatch between your example code and the problem description
you are giving. The example can easily be rewritten without nested scopes
and exec:

# of course untested
def funcB(some_string):
    for r in [regexp1, regexp2, regexp3, ..., regexpN]:
        match = r.match(some_string)
        if match:
            yield match.group(1)
        else:
            yield None 

def funcA():
    k1, k2, k3, ..., kN = funcB(some_string)

The uniform ki variable names are an indication that you may be able to
simplify this even further. I'm therefore confident that rewriting your
real code without exec will be more rewarding than digging deeper into the
quirks of exec (which admittedly I find puzzling, too).

Peter

PS: Here is another gem showing that my original assertion that inside a
function locals() is always a copy is wrong:

>>> def f():
...     locals()["a"] = 42
...     print a
...
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in f
NameError: global name 'a' is not defined
>>> def f():
...     locals()["a"] = 42
...     print a
...     if False: exec ""
...
>>> f()
42




More information about the Python-list mailing list