正确使用具有多重继承的方法重写?
Proper use of method overriding with multiple inheritance?
假设我有两个 class 像 Mp3Player
和 DVDPlayer
我要创建一个新的 class MultiPlayer
继承自两者前 classes.
Mp3Player
和 DVDPlayer
都有一个具有相同签名的方法:
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。
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 方式是什么?
我会显式调用 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')
但我会避免它,因为 它假定 MP3Player
和 MP3Player
的共同祖先之间没有 class 和 play
方法和DVDPlayer
(即这里的object
)。如果稍后您改变主意并引入这样的 class,super(MP3Player, self).play(content)
将调用此 class 的 play
方法,而不是您预期的 DVDPlayer.play
方法。 class 不应该在其基础 classes.
的层次结构中假设任何东西
此外,super(MP3Player, self).play(content)
比DVDPlayer.play(self, content)
更难理解,而且还需要明确的class名称。因此,除了松散的灵活性和清晰度之外,您一无所获。
为了更好地理解 super()
在 Python 中的工作原理,我强烈推荐 Raymond Hettinger 的优秀文章 Python’s super() considered super!
当您使用继承时,您是说子class 是父class的一种类型,只是一种更特殊的类型。这称为 is-a 关系。
一个常见的例子是用动物来说明这一点。假设您有三个 classes:Animal、Cat 和 Lion。狮子 是 猫,而猫 是 动物,因此在这种情况下使用继承是有意义的。
但是你的情况不同。您有一个 MultiPlayer class,通过使用继承,您说它 是 一个 MP3 播放器,而且它 也是 DVD 播放器。
这可以工作,但是在这种情况下使用 组合 而不是 继承 更自然。组合是 has-a 关系而不是 is-a,这意味着您的多人游戏 class has 里面有一个 MP3 播放器,它还有 有 一个 DVD 播放器,但是 根本上 两者都不是.
假设我有两个 class 像 Mp3Player
和 DVDPlayer
我要创建一个新的 class MultiPlayer
继承自两者前 classes.
Mp3Player
和 DVDPlayer
都有一个具有相同签名的方法:
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。
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 方式是什么?
我会显式调用 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')
但我会避免它,因为 它假定 MP3Player
和 MP3Player
的共同祖先之间没有 class 和 play
方法和DVDPlayer
(即这里的object
)。如果稍后您改变主意并引入这样的 class,super(MP3Player, self).play(content)
将调用此 class 的 play
方法,而不是您预期的 DVDPlayer.play
方法。 class 不应该在其基础 classes.
此外,super(MP3Player, self).play(content)
比DVDPlayer.play(self, content)
更难理解,而且还需要明确的class名称。因此,除了松散的灵活性和清晰度之外,您一无所获。
为了更好地理解 super()
在 Python 中的工作原理,我强烈推荐 Raymond Hettinger 的优秀文章 Python’s super() considered super!
当您使用继承时,您是说子class 是父class的一种类型,只是一种更特殊的类型。这称为 is-a 关系。
一个常见的例子是用动物来说明这一点。假设您有三个 classes:Animal、Cat 和 Lion。狮子 是 猫,而猫 是 动物,因此在这种情况下使用继承是有意义的。
但是你的情况不同。您有一个 MultiPlayer class,通过使用继承,您说它 是 一个 MP3 播放器,而且它 也是 DVD 播放器。
这可以工作,但是在这种情况下使用 组合 而不是 继承 更自然。组合是 has-a 关系而不是 is-a,这意味着您的多人游戏 class has 里面有一个 MP3 播放器,它还有 有 一个 DVD 播放器,但是 根本上 两者都不是.