3

I have 2 classes: A (which needs 1 argument to initialize) and B (which needs 2 arguments to initialize), and a third class C which derives from both A and B.

class A:
    def __init__(self, sval): 
        print("A: rcd value: ", sval)
        self.aval = sval

class B: 
    def __init__(self, sval, tval):
        print("B: rcd 2 values: ", sval, tval)
        self.aval=sval
        self.bval=tval

class C(A,B):
    def __init__(self, a, b, c):
        super().__init__(a) 
        super().__init__(b,c) # error here

c = C(1,2,3)

When I run above code, there is error at the last line; __init__ of class A is called, not that of class B.

A: rcd value:  1
Traceback (most recent call last):
  File "inheritance.py", line 20, in <module>
    c = C(1,2,3)
  File "inheritance.py", line 16, in __init__
    super().__init__(b,c) 
TypeError: __init__() takes 2 positional arguments but 3 were given

How can I call __init__ functions of both A and B from __init__ of class C?

Edit: I am using Python 3.5.3 on Debian Linux, though I will prefer a solution which works on both Python2 and Python3.

3
  • I've added a Python-2.x and Python-3.x tag as you never specified which version of Python you were using, and the solution works for both Commented Feb 17, 2019 at 1:56
  • You have a conflict to resolve: both A and B have attributes named aval; one needs to be renamed. If you don't have control over A or B, then you're going to have to define an adaptor for one of them. Commented Feb 17, 2019 at 2:06
  • The right way to use super is to have both A and B use it as well, then use super once from C.__init__. Commented Feb 17, 2019 at 2:07

2 Answers 2

2

Let's assume you have control over A and B and can avoid using the same attribute name in both. Then in order to correctly use super, define them as follows.

class A:
    def __init__(self, aval, **kwargs): 
        print("A: rcd value: ", aval)
        self.aval = sval
        super().__init__(**kwargs)

class B: 
    def __init__(self, b1val, b2val, **kwargs):
        print("B: rcd 2 values: ", b1val, b2val)
        self.b1val = b1val
        self.b2val = b2val
        super().__init__(**kwargs)

Then C.__init__ needs to call super only once:

class C(A, B):
    def __init__(self, aval, b1val, b2val, **kwargs):
        super().__init__(aval=aval, b1val=b1val, b2val=b2val, **kwargs)

c = C(1, 2, 3)
Sign up to request clarification or add additional context in comments.

4 Comments

Any drawbacks of the solution by AK47 ?
At least as written, it doesn't handle the conflicting aval attributes defined in A and B; B.__init__ simply overwrites the value set by A.__init__. Also (again extending this beyond the original question) if A and B shared a common base class, it's __init__ method (assuming both A and B properly called it) would be called twice, which could cause problems, depending on its definition.
In the end, though, both approaches require some care about how the classes involved are defined. I would never say it is absolutely wrong to explicitly call parent class methods instead of using super; you just need to be aware of the pros and cons of each, and use the one most appropriate to your class hierarchy.
Great explanation. I think you can put these comments in your answer itself where they are more likely to be read by other users.
2

Call A.__init__() and B.__init__() instead of super().__init__()

class C(A,B):
    def __init__(self, a, b, c):
        A.__init__(self, a) 
        B.__init__(self, b, c)

Python 3 (https://repl.it/repls/CooperativeTransparentRobot):

class A:
    def __init__(self, sval): 
        print("A: rcd value: ", sval)
        self.aval = sval

class B: 
    def __init__(self, sval, tval):
        print("B: rcd 2 values: ", sval, tval)
        self.aval=sval
        self.bval=tval

class C(A,B):
    def __init__(self, a, b, c):
        A.__init__(self, a) 
        B.__init__(self, b,c) # this does not give error

c = C(1,2,3)

>> Python 3.6.1 (default, Dec 2015, 13:05:11)
>> [GCC 4.8.2] on linux
>> A: rcd value:  1
>> B: rcd 2 values:  2 3

Also works in Python 2: https://repl.it/repls/GreenAbleBlockchain

4 Comments

Can I leave first super call as it is: super().__init__(a) and only use B.__init__(self, b, c) ?
Yes, but dont pass self to super().__init__()
I altered the comment on the line which was giving error earlier. This method works well but answer by @chepner seems much more broad based.
@AK47 Note that when you call B.__init__, it overwrites the aval set by A.__init__. That's not really a problem with using A.__init__ and B.__init__ explicitly, just with C inheriting from two conflicting classes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.