Say I do this in python 3.6:
class A:
class B:
pass
class C:
x = B()
This fails complaining that B
is not defined when instantiating it in C
.
However, this:
class A:
x = 1
y = x
def f(self):
return self
z = f
works fine.
And of course, this:
class A:
pass
class B:
x = A()
also works.
Why do inner classes definitions not follow the same logical rules as everything else?
The problem here is not the definition order, which works like everything else, it is the special nature of class-body scope. Essentially, variables in the class-body scope can only be accessed using the class-namespace, e.g. MyClass.my_class_variable
. The special aspect of it is that it does not create an enclosing scope, which is why you cannot access my_class_variable
and are forced to use the class-namespace inside a method definition, for example. Read more about that in this answer. So again, B
is in fact defined. Note, the following works:
In [4]: class A:
...: class B:
...: pass
...: x = B.__name__
...:
...:
In [5]: A.x
Out[5]: 'B'
Now, you might hope the following would work:
In [6]: class A:
...: class B:
...: pass
...: class C:
...: x = A.B()
...:
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-a145c80eee84> in <module>()
----> 1 class A:
2 class B:
3 pass
4 class C:
5 x = A.B()
<ipython-input-1-a145c80eee84> in A()
2 class B:
3 pass
----> 4 class C:
5 x = A.B()
6
<ipython-input-1-a145c80eee84> in C()
3 pass
4 class C:
----> 5 x = A.B()
6
However, it does not, because A
hasn't actually been defined yet! So, the solution is something like this:
In [7]: class A:
...: class B:
...: pass
...: class C:
...: pass
...:
...:
In [8]: A.C.x = A.B
So, this example should be illuminating:
In [14]: x = 'global'
In [15]: class Foo:
...: x = 'foooooo!'
...: def bar(self):
...: return x
...:
In [16]: Foo().bar()
Out[16]: 'global'
In [17]: Foo.x
Out[17]: 'foooooo!'