When a class definition is encountered Python will execute the body without second thought.
First, it will execute class one
, while executing the body (and before actually creating the class), it will encounter class two
so it will execute that.
Inside class two
it will see a reference to one
which still does not exist, hence a NameError
will be raised.
One simple way to see the difference in the way Python treats classes/functions is by wrapping the second class definition inside a function. Since Python only compiles functions and doesn't execute them, class one
is going to get created:
class one:
x = 1
def wrap():
class two:
y = one.x
one.two = two
Now one
exists as a class. If you execute one.wrap
the second class definition is going to get executed, the one
class is going to be found and then, just to follow along with your original example; I set the class two
as an attribute of one
to get the same effect you were going for.
As a result, name resolution works fine and class two
now has an attribute of class one
:
one.wrap()
one.two.y
Out[22]: 1
Do Note: Moving the second class outside of the first class definition works too, but that's besides the point.