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.