I recently encountered the following phenomenon and couldn't understand why it happens.
Consider the following:
class A:
my_var = 0
def __init__(self):
type(self).my_var = 1
class B(A):
pass
This results in:
In [3]: A.my_var is B.my_var
Out[3]: True
In [4]: A()
In [5]: A.my_var is B.my_var
Out[5]: True
In [6]: A.my_var
Out[6]: 1
In [7]: B.my_var
Out[7]: 1
But then:
In [8]: B()
In [9]: A.my_var is B.my_var
Out[9]: False
In [10]: A.my_var
Out[10]: 1
In [11]: B.my_var
Out[11]: 2
I do not understand why initiazling B(), casues my_var to "fork".
CodePudding user response:
When you call B(), B.__init__ resolves to A.__dict__['init'], since you did not override B.__init__. But type(self) still returns B, because it's an instance of B, not A, being initialized. As a result, you create B.my_var.
The assignment to an attribute is what makes this different from something like x = y, where x has to be defined in the current scope to avoid an UnboundLocalError exception. type(self).my_var = 1 "desugars" to B.my_var = B.my_var 1. (type(self) has to be evaluated first to identify on which type to find the __iadd__ attribute.) On the right-hand side, B.__dict__['my_var'] is not defined, so it evaluates to A.my_var. On the left, the attribute is created.
