exec src in {}, {} strangeness

S

Stefan Seefeld

hi there,

I have trouble running some python code with 'exec':

t.py contains:
class Foo: pass
class Bar:
f = Foo

From a python shell I do:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<string>", line 2, in ?
File "<string>", line 3, in Bar
NameError: name 'Foo' is not defined


However, when I use the current global and local scope, i.e.
simply 'exec f', everything works fine. What am I missing ?

Thanks,
Stefan
 
D

Do Re Mi chel La Si Do

Hi !


Try :

exec f in globals(),locals()
or
exec(f,globals(),locals())
or
exec f in globals(),globals()
or
exec(f,globals(),globals())



@-salutations

Michel Claveau
 
S

Stefan Seefeld

Do said:
Hi !


Try :

exec f in globals(),locals()
or
exec(f,globals(),locals())
or
exec f in globals(),globals()
or
exec(f,globals(),globals())

Indeed, using 'globals()' and 'locals()' works. However,
both report the same underlaying object, which is a bit
confusing. (Under what circumstances does 'locals()' return
not the same object as 'globals()' ?)

The problem appears to be that

exec f in a, b

where a and b are distinct dictionaries, does not look up
symbols in 'a' when in local scope.
I filed a bug report (#1167300).

Regards,
Stefan
 
P

Peter Hansen

Stefan said:
Indeed, using 'globals()' and 'locals()' works. However,
both report the same underlaying object, which is a bit
confusing. (Under what circumstances does 'locals()' return
not the same object as 'globals()' ?)

When you aren't at the interactive prompt... there are
no "locals" there, so locals() just maps through to globals().
(Probably this applies to all code at the module level,
as oppsed to code inside any callable, but I haven't
verified... you can easily enough.)

Does this information invalidate your bug report?

-Peter
 
S

Stefan Seefeld

Peter said:
When you aren't at the interactive prompt... there are
no "locals" there, so locals() just maps through to globals().
(Probably this applies to all code at the module level,
as oppsed to code inside any callable, but I haven't
verified... you can easily enough.)

Does this information invalidate your bug report?

No, but that's possibly only because I don't (yet) understand
the implications of what you are saying.

Is there anything wrong with 'exec source in a, b' where
a and b are distinc originally empty dictionaries ? Again,
my test code was

class Foo: pass
class Bar:
foo = Foo

and it appears as if 'Foo' was added to 'a', but when evaluating
'foo = Foo' the interpreter only looked in 'b', not 'a'.

Thanks,
Stefan
 
B

Bernhard Herzog

Stefan Seefeld said:
Is there anything wrong with 'exec source in a, b' where
a and b are distinc originally empty dictionaries ? Again,
my test code was

class Foo: pass
class Bar:
foo = Foo

and it appears as if 'Foo' was added to 'a', but when evaluating
'foo = Foo' the interpreter only looked in 'b', not 'a'.

No, it's the other way round. Foo is added in b since bindings are done
in the local scope. Your case is a bit more complicated, though.
Here's what I think happens:

class Foo is bound in b, the locals dictionary, so there is no reference
to Foo in the globals dictionary. The body of class B is executed with
it's own new locals dictionary. That locals dictionary will effectively
be turned into Bar.__dict__ when the class object is created.

When "foo = Foo" is executed, Foo is first looked up in that new locals
dictionary. That fails, so it's also looked up in the globals
dictionary a. That fails as well because Foo was bound in b. The final
lookup in the builtins also fails, and thus you get an exception.


Bernhard
 
S

Stefan Seefeld

Bernhard said:
No, it's the other way round. Foo is added in b since bindings are done
in the local scope. Your case is a bit more complicated, though.
Here's what I think happens:

class Foo is bound in b, the locals dictionary, so there is no reference
to Foo in the globals dictionary. The body of class B is executed with
it's own new locals dictionary. That locals dictionary will effectively
be turned into Bar.__dict__ when the class object is created.

When "foo = Foo" is executed, Foo is first looked up in that new locals
dictionary. That fails, so it's also looked up in the globals
dictionary a. That fails as well because Foo was bound in b. The final
lookup in the builtins also fails, and thus you get an exception.

Thanks for the explanation ! I'm still unable to make a conclusion:
What is wrong ? Am I doing something stupid (I did try various things
such as inserting __builtin__ into the dictionary, etc.) ?
Or is that really a bug ?

Thanks,
Stefan
 
G

Greg Ewing

Yes, from the experiment I just did, that does seem to
be what is happening.
Thanks for the explanation ! I'm still unable to make a conclusion:
What is wrong ? Am I doing something stupid...? Or is that really a bug?

It seems to be a hangover from the old two-scope system
where local scopes didn't nest. It probably qualifies as
a bug, since it differs from the modern behaviour of
a class definition inside the local scope of a function.

However, if your intention is to define the classes in
the global dict then yes, you are doing something wrong --
you should be passing the same dictionary for both scopes:

g = {}
exec stuff_to_define in g, g
# definitions are now in g
 
B

Brano Zarnovican

As Greg pointed..

g = {}
exec open('t.py').read() in g, g

is what you want.

But you can write it also this way:
exec open('t.py').read() in {}

because if you specify only globals, the same
dictionary is also used for locals. (locals() is
used as a default only if you don't specify globals)

OR

explicitly move class Foo to globals

t.py contains:
globals Foo
class Foo: pass
class Bar:
f = Foo

(Should work. I haven't tried it, though)

BranoZ
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

use of exec() 12
exec with custom dict 0
imports and exec 2
Problem with exec 2
Problem with exec 0
Problem with exec 10
Replacing globals in exec by custom class 5
Can I reflect to get arguments exec()? 0

Members online

No members online now.

Forum statistics

Threads
474,228
Messages
2,571,157
Members
47,785
Latest member
deepusaini

Latest Threads

Top