正确使用多重继承覆盖的方法?



假设我有两个类,如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),因为基于 MRO 规则,它总是解析为MP3Player中的play方法。

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

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

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

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

这可以工作,但是在这种情况下使用组合而不是继承更自然。 组合是一种has-a关系而不是is-a,这意味着您的 MultiPlayer 类内部有一个MP3 播放器,并且它内部还有一个 DVD 播放器,但从根本上说,它不是这两件事。

我会显式调用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方法的类(也就是说object这里(。如果以后你改变主意并引入这样一个类,super(MP3Player, self).play(content)将调用这个类的play方法,而不是你打算的DVDPlayer.play方法。 类永远不应该在其基类的层次结构中假定任何内容。

此外,super(MP3Player, self).play(content)DVDPlayer.play(self, content)更难理解,并且还需要显式的类名。因此,您只能获得松散的灵活性和清晰度。

为了更好地理解super()在 Python 中是如何工作的,我强烈推荐 Raymond Hettinger 的优秀文章Python 的 super(( 被认为是 super!

相关内容

  • 没有找到相关文章

最新更新