Misha
Misha

Reputation: 41

python class inheritance: constructor of derived class issue

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

Answers (2)

unutbu
unutbu

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

jfaller
jfaller

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

Related Questions