Because B's constructor initializes the instance field x
to the value of the global x
("dog"
), not the class field x
.
If you wanted it to initialize an instance field with the class field, you'd do
def __init__(self):
self.x = self.__class__.x
(and in fact, the non-sensical-looking
def __init__(self):
self.x = self.x
would do the same thing.)
As a related aside, it's good to understand the relation between instance fields and class fields:
class A:
kind = "cat"
class B(A):
kind = "ferret"
def __init__(self):
self.kind = self.kind
a1 = A()
a2 = A()
print(f"{a1.kind = } {a2.kind = }")
A.kind = "big cat" # changes the class field, so all As are big from now on:
print(f"{a1.kind = } {a2.kind = }")
a1.kind = "medium cat" # assigns a new instance field just to a1
print(f"{a1.kind = } {a2.kind = }")
b1 = B()
b2 = B()
print(f"{b1.kind = } {b2.kind = }")
# this has no effect on existing Bs since they copied the value from the class field:
B.kind = "hamster"
print(f"{b1.kind = } {b2.kind = }")
# However new bs will copy that new hamster value:
b3 = B()
print(f"{b1.kind = } {b2.kind = } {b3.kind = }")
This prints out
a1.kind = 'cat' a2.kind = 'cat'
a1.kind = 'big cat' a2.kind = 'big cat'
a1.kind = 'medium cat' a2.kind = 'big cat'
b1.kind = 'ferret' b2.kind = 'ferret'
b1.kind = 'ferret' b2.kind = 'ferret'
b1.kind = 'ferret' b2.kind = 'ferret' b3.kind = 'hamster'