Reputation: 271
I was confident to have at least some basic understanding of Python's scope system. Now I get an error and unfortunately I'm not even able to write a good code snippet for reproduction so far. I tried to reproduce it in a new small project, but everything works as I expect there :-/
I can only describe what I do and hopefully somebody detects a pattern and can tell me what possibly goes wrong here.
At first there is a python file x.py
which implements a class X
.
In some other python file, there is the following string:
code="""
...
from x import X
...
class Y(X): # does not crash here, ...
def __init__(self):
X.__init__(self) # ... but here
...
foo=Y()
"""
You can assume that python is able to find the x
module. At some place, I try to execute that:
exec(code, globals(), locals())
And now I get the NameError
. It tells me that X
is not defined when it tries to call it's constructor. It was obviously defined a few lines above.
If I modify Y.__init__
with adding from x import X
as first line, it works. But why the hell do I have to import it again there?
As already indicated, the actual code is more complex and does more things. In an unlucky case, my posting does not even show the part which actually leads to the problem. But maybe you have some general ideas, how one can get such a behaviour.
Upvotes: 11
Views: 13579
Reputation: 365707
This is just a guess, because you haven't shown us enough code, and what you've shown us doesn't actually reproduce the problem, but…
If you're doing this exec
inside a function, then locals()
and globals()
are going to be different. In which case the code will be executed as if it were inside a class definition. So, it'll be (sort of) as if you did this:
class _:
from x import X
class Y(X): # does not crash here, ...
def __init__(self):
X.__init__(self) # ... but here
foo=Y()
del _
(I previously thought you'd have to also be doing something like Y()
outside the exec
, but user2357112's answer convinced me that isn't necessary.)
If that's your problem, you may be able to fix it by just calling exec(code, globals(), globals())
or exec(code, locals(), locals())
. (Which one is appropriate, if either, depends on what you're actually trying to do, of course, which you haven't told us.)
Upvotes: 10
Reputation: 280544
From the exec
documentation:
If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.
There are good reasons for this, which I won't go into here.
Functions defined in a class definition don't look in the scope of the class definition for variable resolution. When you exec
your code
, it's actually executed like this:
class Dummy:
from x import X
...
class Y(X):
def __init__(self):
X.__init__(self)
...
foo=Y()
That means this function:
def __init__(self):
X.__init__(self)
doesn't see this variable:
from x import X
even though this bit:
class Y(X):
does see it.
Upvotes: 8