3

Assume I have two classes like Mp3Player, and DVDPlayer and I am going to create a new class MultiPlayer which inherits from both former classes.

Mp3Player and DVDPlayer both have a method with same signature:

class MP3Player:

    def play(self, content):
        print(f'MP3 player is playing {content}')


class DVDPlayer:

    def play(self, content):
        print(f'DVD player is playing {content}')

I want to override the play method in MultiPlayer and I want to be able to call the appropriate super class, based on some conditions.

class MultiPlayer(MP3Player, DVDPlayer):

    def play(self, content):
        if mp3_condition:
            # some how call the play method in MP3Player
        elif dvd_condition:
            # some how call the play method in DVDPlayer
        else:
            print('the given content is not supported')

I cannot use super().play(content) as based on MRO rules it always resolves to play method in MP3Player.

What is the pythonic way of doing such thing?

2
  • 4
    I'm not sure it necessarily makes sense to use multiple inheritance in this case. Maybe use a kind of wrapper pattern instead, where MultiPlayer has internal attributes which are instances of MP3Player and DVDPlayer. Commented Aug 18, 2019 at 19:29
  • Yeah, that's possible. But I am trying to understand multiple inheritance in python and I want to know if this scenario happens what's the proper way of handling it. Commented Aug 18, 2019 at 19:32

2 Answers 2

3

When you use inheritance, you're saying that the subclass is a type of the parent class, just a more specialized one. This is called an is-a relationship.

One common example uses animals to illustrate this. Imagine you have three classes: Animal, Cat, and Lion. A lion is a cat, and a cat is an animal, so it makes sense to use inheritance in this context.

However your situation is different. You have a MultiPlayer class, and by using inheritance, you're saying that it is an MP3 player, and it also is a DVD player.

This can work, however it's more natural in this case to use composition instead of inheritance. Composition is a has-a relationship instead of is-a, meaning that your MultiPlayer class has an MP3 player inside of it, and it also has a DVD player inside of it, but it is not fundamentally either of those things.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks John for your instructive answer. Are you inferring that such scenario may not happen if we use inheritance in its proper place?
Yes. Inheritance is tricky to use properly, and mutliple inheritance much more so.
2

I would call the play methods explicitly:

class MultiPlayer(MP3Player, DVDPlayer):

    def play(self, content):
        if mp3_condition:
            MP3Player.play(self, content)
        elif dvd_condition:
            DVDPlayer.play(self, content)
        else:
            print('the given content is not supported')

Note. — If you absolutely wanted to use super(), you could do that:

class MultiPlayer(MP3Player, DVDPlayer):

    def play(self, content):
        if mp3_condition:
            super().play(content)
        elif dvd_condition:
            super(MP3Player, self).play(content)
        else:
            print('the given content is not supported')

But I would avoid it as it assumes there is no class with a play method between MP3Player and the common ancestor of MP3Player and DVDPlayer (that is to say object here). If later you change your mind and introduce such a class, super(MP3Player, self).play(content) will call the play method of this class instead of the DVDPlayer.play method as you intended. A class should never assume anything on the hierarchy of its base classes.

In addition, super(MP3Player, self).play(content) is harder to understand than DVDPlayer.play(self, content), and it also requires an explicit class name. So you gain nothing but loose flexibility and clarity.

To better understand how super() works in Python, I highly recommend Raymond Hettinger's excellent article Python’s super() considered super!

8 Comments

Is it appropriate to access instance methods thorough class names? I thought we use class names to access static methods and class attributes.
You need to pass the content argument when you call the play methods.
@Ehsan Yes it is perfectly appropriate to access bound methods through classes.
thanks @Maggyero for the side note, but super(MP3Player, self).play(content) won't work as the super class of MP3Player is object which does not have play method.
@Ehsan It is for MultiPlayer, since its __mro__ is: (<class 'MultiPlayer'>, <class 'MP3Player'>, <class 'DVDPlayer'>, <class 'object'>). Try the code and you will see.
|

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.