473,385 Members | 1,387 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

A problem with exec statement

TPJ
I have the following code:

-----------------------------------
def f():

def g():
a = 'a' # marked line 1
exec 'a = "b"' in globals(), locals()
print "g: a =", a

a = 'A' # marked line 2
exec 'a = "B"' in globals(), locals()
print "f: a =", a
g()

f()
-----------------------------------

I don't understand, why its output is:

f: a = A
g: a = a

instead of:

f: a = B
g: a = b

All works as intended, if the marked lines are commented out. I just
don't understand, why. (I suppose I don't understand, how the exec
statement works, or the way Python handles objects, their names and
namespaces...) In my opinion (according to my knowledge about Python),
with or without the marked lines commented, the code should work the
same. Well - I think I have to learn more about Python...

According to my knowledge, the most important are the namespaces: the
local ones, in this case. When Python calls the f function, its
namespace is created. This namespace contains only the g function.
Then the a variable is created (and the "a" name is added to the f
function namespace).

The next statement is the exec one. Since the statement "knows" the
local namespace (obtained from the locals() function), it should
replace the value of the a variable in the local namespace with the
value of the new string "B". I don't understand, why this is not done.

The situation in the g function is similar, the only difference is
that the local namespace contains the "a" name, that refers to a
different Python object.

Apr 14 '06 #1
5 2414
TPJ wrote:
I have the following code:

-----------------------------------
def f():

**def*g():
****a*=*'a'*************#*marked*line*1
****exec*'a*=*"b"'*in*globals(),*locals()
****print*"g:*a*=",*a

**a*=*'A'***************#*marked*line*2
**exec*'a*=*"B"'*in*globals(),*locals()
**print*"f:*a*=",*a
**g()

f()
-----------------------------------

I don't understand, why its output is:

f: a = A
g: a = a

instead of:

f: a = B
g: a = b


Use the exec statement without the in-clause to get the desired effect:
def f(): .... a = "a"
.... exec "a = 'B'"
.... print a
.... f() B

Inside a function locals() creates a new dictionary with name/value pairs of
the variables in the local namespace every time you call it. When that
dictionary is modified the local variables are *not* updated accordingly.
def f(): .... a = "a"
.... d = locals()
.... exec "a = 'B'" in globals(), d
.... print a, d["a"]
.... f()

a B

By the way, experiments on the module level are likely to confuse because
there locals() returns the same dictionary as globals().

Peter
Apr 14 '06 #2
TPJ wrote:
I have the following code:

-----------------------------------
def f():

def g():
a = 'a' # marked line 1
exec 'a = "b"' in globals(), locals()
print "g: a =", a

a = 'A' # marked line 2
exec 'a = "B"' in globals(), locals()
print "f: a =", a
g()

f()
-----------------------------------

I don't understand, why its output is:

f: a = A
g: a = a

instead of:

f: a = B
g: a = b

All works as intended, if the marked lines are commented out. I just
don't understand, why. (I suppose I don't understand, how the exec
statement works, or the way Python handles objects, their names and
namespaces...) In my opinion (according to my knowledge about Python),
with or without the marked lines commented, the code should work the
same. Well - I think I have to learn more about Python...
That's true of almost everybody reading this list, myself included.
According to my knowledge, the most important are the namespaces: the
local ones, in this case. When Python calls the f function, its
namespace is created. This namespace contains only the g function.
Then the a variable is created (and the "a" name is added to the f
function namespace).
That's a pretty good summary. In fact just after the call to f is
started its namespace doesn't even contain "g", that's added by
executing the def statement that defines g.

The assignment does indeed create the name "a" in the function's (local)
namespace.
The next statement is the exec one. Since the statement "knows" the
local namespace (obtained from the locals() function), it should
replace the value of the a variable in the local namespace with the
value of the new string "B". I don't understand, why this is not done.
So when you exec 'a = "B"' in globals(), locals() you might think you
were changing the local namespace. In fact you are changing a *copy* of
the local namespace: if you read the documentation carefully you will
see under locals() it says """Warning: The contents of this dictionary
should not be modified; changes may not affect the values of local
variables used by the interpreter."""
The situation in the g function is similar, the only difference is
that the local namespace contains the "a" name, that refers to a
different Python object.

The same answer presumably pertains here. If you modify your code to read:

def f():

def g():
a = 'a' # marked line 1
print "globals:", globals(), '\nlocals:', locals()
exec 'a = "b"' in globals(), locals()
print "globals:", globals(), '\nlocals:', locals()
print "g: a =", a

a = 'A' # marked line 2
print "Globals:", globals(), '\nLocals:', locals()
exec 'a = "B"' in globals(), locals()
print "Globals:", globals(), '\nLocals:', locals()
print "f: a =", a
g()

f()

you will see quite clearly that you aren't making the changes you
anticipate to the local namespace. I hope I have explained why.

One last note. Newcomers to Python often seem fascinated by the ability
to use exec to achieve namespace indirection. 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.

regards
Steve

--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd www.holdenweb.com
Love me, love my blog holdenweb.blogspot.com

Apr 14 '06 #3
TPJ
> Use the exec statement without the in-clause to get the desired effect:
def f(): ... a = "a"
... exec "a = 'B'"
... print a
... f()

B
<snip>


Well... I *do* realize that. But this is *not* my problem. I have a
function with another nested one. If I used "exec ..." instead of "exec
.... in some_dict, some_dict" I would get the "SyntaxError: unqualified
exec is not allowed in function 'f' it contains a nested function with
free variables".

To be honest, the message cited above is the answer to the question
"Why have I put those globals(), locals() in the exec statments?".

Apr 14 '06 #4
TPJ
> <snip>
So when you exec 'a = "B"' in globals(), locals() you might think you
were changing the local namespace. In fact you are changing a copy of
the local namespace:
<snip>
Well, that explains much, but not all that I want to be explained. Why?
Because now I understand, that by invoking

exec "a = 'B'" in globals(), locals()

I can modify only *copies* of the global and local namespaces dicts,
not the dicts themselves. OK, that's why my code doesn't work as I want
it to work.

But why on Earth *the same code* will work, if I remove the assignments
from the marked lines? Why then operating on copies of the local
namespaces dicts *will work* ?
(...) 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()

Of course, the code presented above doesn't work. It works, if one
change is done in the function funcB:

def funcB():
...
# no creation of any local variables called var1, var2, ..., varN
here
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()
else:
# here we put the code, that will assign None to the variable
exec var_name + ' = None'
return var1, var2, var3, ..., varN

But I *still* don't understand, why this code works, if I operate on a
copy of the local namespace dict...

Of course, I can do the same thing in a different matter - by using a
dictionary. And perhaps I will. But I still want to know, how the exec
statement works.

* * *

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?

Apr 14 '06 #5
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

Apr 15 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: Toby Donaldson | last post by:
Hi all, I'm designing an educational application that will run Python code and check the output against a pre-define answer. I want to use the "exec" statement to run the code, but I don't know...
2
by: tedsuzman | last post by:
----- def f(): ret = 2 exec "ret += 10" return ret print f() ----- The above prints '12', as expected. However,
45
by: It's me | last post by:
I am new to the Python language. How do I do something like this: I know that a = 3 y = "a" print eval(y)
2
by: Caro | last post by:
I have a stored procedure spGetAccessLogDynamic and when I try to call it I get the following error: Server: Msg 2812, Level 16, State 62, Line 1 Could not find stored procedure 'S'. I dont...
4
by: technocrat | last post by:
I am trying to update a million rows in a table and doing this reading from a file which has the record pkids and constructing a preparedstatemtn with that pkid and adding it to the batch......
3
by: Thomas Heller | last post by:
I'm using code.Interactive console but it doesn't work correctly with non-ascii characters. I think it boils down to this problem: Python 2.4.3 (#69, Mar 29 2006, 17:35:34) on win32 Type...
2
by: chets | last post by:
Hi All, I am facing problem in executing one dynamic query in PRO *C program on linux. I want to update table mytable by data MADURAI for a column mycolumn1 where primary key is myPK.I want to...
3
by: Abel Daniel | last post by:
Hi! A python interactive interpreter works by having the user type in some code, compiling and running that code, then printing the results. For printing, the results are turned into strings. ...
7
by: Frank Swarbrick | last post by:
Is there a way to do a multi-row fetch in to a COBOL table with DB2/LUW? Apparently the following is supported in z/OS, but not LUW (or at least I couldn't get it to work): WORKING-STORAGE...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.