【问题标题】:Proper use of method overriding with multiple inheritance?正确使用多重继承的方法覆盖?
【发布时间】:2019-12-24 03:21:28
【问题描述】:

假设我有两个类,如 Mp3PlayerDVDPlayer,我将创建一个新类 MultiPlayer,它继承自之前的两个类。

Mp3PlayerDVDPlayer 都有一个签名相同的方法:

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}')

我想重写MultiPlayer 中的play 方法,并且我希望能够根据某些条件调用适当的超类。

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')

我不能使用super().play(content),因为它总是解析为MP3Player 中的play 方法。

做这种事情的pythonic方式是什么?

【问题讨论】:

  • 我不确定在这种情况下使用多重继承是否有意义。也许可以改用一种包装器模式,其中MultiPlayer 具有内部属性,它们是MP3PlayerDVDPlayer 的实例。
  • 是的,这是可能的。但我想了解python中的多重继承,我想知道这种情况是否发生,处理它的正确方法是什么。

标签: python python-3.x overriding multiple-inheritance


【解决方案1】:

当你使用继承时,你是说子类父类的一种类型,只是一种更特殊的类型。这称为 is-a 关系。

一个常见的例子使用动物来说明这一点。假设您有三个类:Animal、Cat 和 Lion。狮子猫,猫动物,所以在这种情况下使用继承是有意义的。

但是你的情况不同。你有一个 MultiPlayer 类,通过使用继承,你说它一个 MP3 播放器,它也是一个一个 DVD 播放器。

这可以工作,但是在这种情况下使用 composition 而不是 inheritance 更自然。组合是 has-a 关系,而不是 is-a,这意味着您的 MultiPlayer 类 内部有一个 MP3 播放器,并且它也里面有一个 DVD 播放器,但它根本上不是这些东西。

【讨论】:

  • 感谢约翰的指导性回答。您是否推断如果我们在适当的地方使用继承,这种情况可能不会发生?
  • 是的。继承很难正确使用,多重继承更是如此。
【解决方案2】:

我会明确调用play 方法:

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')

注意。 — 如果您绝对想使用 super(),您可以这样做:

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')

但我会避免它,因为 它假定在 MP3PlayerMP3PlayerDVDPlayer 的共同祖先之间没有带有 play 方法的类(也就是说 @ 987654330@ 这里)。如果以后你改变主意引入这样一个类,super(MP3Player, self).play(content) 将调用这个类的play 方法,而不是你想要的DVDPlayer.play 方法。一个类不应该在其基类的层次结构上假设任何东西。

另外,super(MP3Player, self).play(content)DVDPlayer.play(self, content) 更难理解,而且它还需要一个显式的类名。所以你得到的只是松散的灵活性和清晰度。

为了更好地理解 super() 在 Python 中的工作原理,我强烈推荐 Raymond Hettinger 的优秀文章 Python’s super() considered super!

【讨论】:

  • 通过类名访问实例方法是否合适?我以为我们使用类名来访问静态方法和类属性。
  • 调用play方法时需要传递content参数。
  • @Ehsan 是的,通过类访问绑定方法非常合适。
  • 感谢@Maggyero 的旁注,但super(MP3Player, self).play(content) 将不起作用,因为MP3Player 的超类是object,它没有play 方法。
  • @Ehsan 它MultiPlayer,因为它的__mro__ 是:(<class 'MultiPlayer'>, <class 'MP3Player'>, <class 'DVDPlayer'>, <class 'object'>)。试试代码,你会看到。
猜你喜欢
  • 2019-10-01
  • 2015-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-20
  • 1970-01-01
  • 2016-06-04
  • 2016-01-25
相关资源
最近更新 更多