Python: weird "NameError: name ... not defined" in the "exec" environment

I was sure that I had at least some basic understanding of the Python visibility system. Now I get an error message and, unfortunately, I can not write a good piece of code for playback yet. I tried to reproduce it in a new small project, but everything works as I expect, there: - /

I can only describe what I am doing, and I hope someone discovers a sample and can tell me what may be going wrong.

First there is a python x.py file that implements class X

In another python file, the following line exists:

 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 can find the X module. At some point, I'm trying to accomplish this:

 exec(code, globals(), locals()) 

And now I get a NameError . He tells me that X not defined when he tries to call its constructor. Obviously, a few lines were defined above.

If I change Y.__init__ with the addition of from x import X to the first line, it works. But why the hell should I import it there?

As already stated, the actual code is more complex and does more things. In an unsuccessful case, my publication does not even show the part that actually leads to the problem. But perhaps you have some general ideas on how to achieve this behavior.

+6
source share
2 answers

This is just an assumption because you did not show us enough code, and what you showed us does not really reproduce the problem, but ...

If you execute this exec inside a function, then locals() and globals() will be different. In this case, the code will be executed as if it were inside the class definition. So this will 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 would have to do something like Y() outside of exec , but user2357112's answer convinced me that this was not necessary.)

If this is your problem, you can fix it simply by calling exec(code, globals(), globals()) or exec(code, locals(), locals()) . (Which one is appropriate if both of them depend on what you are actually trying to do, of course that you did not tell us.)

+3
source

From the exec documentation :

If exec receives two separate objects in the form of global and local, the code will be executed as if it were embedded in the class definition.

There are good reasons for this, and I will not enter here.

Functions defined in a class definition are not considered in the scope of a class definition to resolve variables. When you exec your code , it actually executes as follows:

 class Dummy: from x import X ... class Y(X): def __init__(self): X.__init__(self) ... foo=Y() 

This means that this function:

 def __init__(self): X.__init__(self) 

does not see this variable:

 from x import X 

although this bit:

 class Y(X): 

sees it.

+4
source

Source: https://habr.com/ru/post/986333/


All Articles