473,739 Members | 7,912 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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 2435
TPJ wrote:
I have the following code:

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

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

**a*=*'A'****** *********#*mark ed*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.blogs pot.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 "SyntaxErro r: 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_stri ng):
for r in [regexp1, regexp2, regexp3, ..., regexpN]:
match = r.match(some_st ring)
if match:
yield match.group(1)
else:
yield None

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

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
5778
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 how to get output from it. For instance, exec works like this: >>> code = """ for i in xrange(1, 5):
2
4187
by: tedsuzman | last post by:
----- def f(): ret = 2 exec "ret += 10" return ret print f() ----- The above prints '12', as expected. However,
45
2676
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
5728
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 know why because I dont have anything refering to stored procedure 'S' I have ran my SQL String with sample values and it works fine. So I
4
4808
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... count is the recordnumber read from the file... so for every count the st is added to the batch.....since for every record read from the file has a update statement(st)... st.setString(1, arg1); st.setString(2, arg2); st.setString(3, arg3);
3
6244
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 "help", "copyright", "credits" or "license" for more information. >>> print u"ä" ä >>> exec 'print u"ä"' Traceback (most recent call last): File "<stdin>", line 1, in ?
2
4672
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 use EXECUTE IMMEDIATE with context.But it is not working. Following is my piece of code. Please help. Thanks in advance. int main() {
3
1679
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. I would like make an interpreter which does this, without the last part: i.e. where the results are returned as objects, instead of as strings. I.e. have I would like to see something that behaves like this:
7
6833
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 SECTION. EXEC SQL INCLUDE SQLCA END-EXEC EXEC SQL BEGIN DECLARE SECTION
0
8792
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9479
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9337
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
9209
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8215
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6054
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4826
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3280
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2748
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.