Reputation: 41
I have two classes: a base class A and the derived class B. In the constructor of B I tried to use the constructor of A to initialize the instance. Why assignment "self = A(x)" in constructor of the derived class does not work?
class A:
def __init__(self, x=0):
print "constructing A"
self.x = x
def printx(self):
print "x =",self.x
class B(A):
def __init__(self,x):
A.__init__(self)
print "constructing B"
self = A(x)
self.printx()
b = B(2)
b.printx()
The output:
constructing A
constructing B
constructing A
x = 2
x = 0
Upvotes: 0
Views: 711
Reputation: 879451
In Python, think of variable names (like self
) as "pointing at" or "referencing" values. When you make an instance of B
:
b = B(2)
The B.__init__
method is called with the variable self
already assigned to the inchoate instance of B
. Now, inside this method, when Python reaches
self = A(x)
the variable self
gets reassigned to a new instance of A
. The instance of B
still exists; self
just no longer points to it.
Note that self
is a variable like any other in Python. (self
is not a keyword, it is only a convention that the first argument to methods is called self
.)
By the way, to initialize self
with the value of x
, use
class B(A):
def __init__(self,x):
A.__init__(self, x) # <-- Note the x
print "constructing B"
self.printx()
Then
b = B(2)
b.printx()
yields
constructing A
constructing B
x = 2
x = 2
When a class has an alternate constructor, such as getA
, a typical pattern in Python is to use a classmethod:
class A(object):
def __init__(self, x=0):
print "constructing A"
self.x = x
def printx(self):
print "x =",self.x
@classmethod
def getA(cls, x):
print('constructing getA')
self = cls(x)
self.y = 1
return self
Now to make an instance of A
with the classmethod getA
, you'd say
a = A.getA(x)
The class A
is passed as the first argument to the classmethod getA
, and stored in the variable cls
.
What is beautiful about doing it this way (instead of using a factory function getA
), is that if you subclass A
like this:
class B(A):
def __init__(self,x):
A.__init__(self, x)
print "constructing B"
self.printx()
then you can make instances of B
using the getA
classmethod as well:
b = B.getA(2)
yields
constructing getA
constructing A
constructing B
x = 2
and
print(type(b))
print(b.y)
yields
<class '__main__.B'> # b is an instance of B
1 # showing the y attribute has been set.
Upvotes: 1
Reputation: 508
You don't want to call the constructor in B.__init__
, and you should pass x
to A.__init__
class A:
def __init__(self, x=0):
print "constructing A"
self.x = x
def printx(self):
print "x =",self.x
class B(A):
def __init__(self,x):
A.__init__(self, x)
print "constructing B"
self.printx()
Upvotes: 2