Inherit same function name from several classes

Question:

I was reading on this thread on stackoverflow but it looked like the solution was wrong according to a user and most important, it couldnt solve my question and I dont know if its because the answer is in python 2 or whatnow.

However, lets say i have this code

class A:
    def say_hello(self):
        print("Hi")

class B:
    def say_hello(self):
        print("Hello")

class C(A, B):
    def say_hello(self):
        super().say_hello()
        print("Hey")

welcome = C()
welcome.say_hello()

How can i call both class A and B from class C without changing the names of the functions?
As i read in the other thread you could do something like super(B, self).say_hello() but that does not seem to work, I dont know why though.

Asked By: PlayPhil1

||

Answers:

To use super properly, every class involved needs to be designed correctly. Among other things:

  1. One class should be the “root” for the method, meaning it will not use super to delegate calls further. This class must appear after any other class providing the method.

  2. All classes that are not the root must use super to pass call the method from any other class that might define the method.


# Designated root class for say_hello
class A:
    def say_hello(self):
        print("Hi")

# Does not inherit say_hello, but must be aware that it is not the root
# class, and it should delegate a call further up the MRO
class B:
    def say_hello(self):
        super().say_hello()
        print("Hello")

# Make sure A is the last class in the MRO to ensure all say_hello
# methods are called.
class C(B, A):
    def say_hello(self):
        super().say_hello()
        print("Hey")

welcome = C()
welcome.say_hello()

Here, super in C.say_hello will call B.say_hello, whose super will call A.say_hello.


If you don’t want go along with the requirements for using super, just call the other class’s methods explicitly. There is no requirement to use super.

class A:
    def say_hello(self):
        print("Hi")

class B:
    def say_hello(self):
        print("Hello")

class C(A, B):
    def say_hello(self):
        A.say_hello(self)
        B.say_hello(self)
        print("Hey")
Answered By: chepner

If you don’t want to decide which class (A or B) is the designated root class, you can also implement an abstract superclass for both A and B.

from abc import ABC, abstractmethod

class ISayHello(ABC):
    @abstractmethod
    def say_hello(self):
        pass
 
class A(ISayHello):
    def say_hello(self):
        super().say_hello()
        print("Hi")


class B(ISayHello):
    def say_hello(self):
        super().say_hello()
        print("Hello")
 
 
class C(B,A):
    def say_hello(self):
        super().say_hello()
        print("Hey")

welcome_c = C() 
welcome_c.say_hello()

This would make sense if you have an additional class D with different root class than C.

class D(A,B):
    def say_hello(self):
        super().say_hello()
        print("Hey")

welcome_d = D() 
welcome_d.say_hello()
Answered By: RaimiSol