Why is my superclass calling my subclass method?

James Wang Source

When I call a method that was overrided from my constructor, I am getting an error and it says that it is missing an argument (due to the subclass requiring a second argument). However, I called the method in the super(), so why doesn't it call the super class version of that method?

This is best illustrated with a short example:

class A:
    def __init__(self):
        self.do()

    def do(self):
        print("A")


class B(A):
    def __init__(self):
        super().__init__()
        self.do("B")

    def do(self, arg2):
        super().do()
        print(arg2)


b = B()

Here is the error I get:

Traceback (most recent call last):
    File "D:/Python/Advanced/randomStuff/supersub.py", line 19, in <module>
        b = B()
    File "D:/Python/Advanced/randomStuff/supersub.py", line 11, in __init__
        super().__init__()
    File "D:/Python/Advanced/randomStuff/supersub.py", line 3, in __init__
        self.do()
TypeError: do() missing 1 required positional argument: 'arg2'

It seems to be calling the do() method in class B, but I want to call the do() method in Class A. Ideally, the code should print:

A
A
B

What am I doing wrong?

pythoninheritanceoverridesubclasssuperclass

Answers

answered 3 months ago Patrick Rutz #1

This is really curious. I don't have a solution but the below appears to work as intended. It is exactly the same except for super() is called explicitly with self.class as an argument, which I thought was implicit.

Maybe a more skilled Pythonista can build on this observation.

class A:
    def __init__(self):
        self.do()

    def do(self):
        print("A")

class B(A):
    def __init__(self):
        super(self.__class__).__init__()
        self.do("B")

    def do(self, arg2):
        super().do()
        print(arg2)

print('***init A***')
a = A()
print('***init B***')
b = B()
print('***A.do()***')
a.do()
print('***B.do()***')
b.do('test')

answered 3 months ago see sharper #2

The answer is that a base class that calls a method that is defined on itself, but also overridden by a subclass, calls the overridden method on the subclass not the method on the base class. For further information see calling an overridden method from base class?. See the below variant of your code and follow the logic as described above.

class A:
    def __init__(self):
        self.do()

    def do(self):
        print("do A")


class B(A):
    def __init__(self):
        super().__init__()
        self.do()

    def do(self):
        super().do()
        print("do B")


b = B()

Result: A B A B

comments powered by Disqus