这是我计划用于游戏的代码。但它抱怨MRO错误。我不知道为什么。有人能为我解释一下吗?非常感谢。
class Player:
pass
class Enemy(Player):
pass
class GameObject(Player, Enemy):
pass
g = GameObject()
答案 0 :(得分:85)
您的GameObject
继承自Player
和 Enemy
。因为Enemy
已经继承自Player
Python现在无法确定首先查找方法的类; Player
或Enemy
上的Player
,会覆盖Enemy
中定义的内容。
您不需要在此处命名class GameObject(Enemy):
pass
的所有基类;只从这一个类继承:
Enemy
Player
已包含{{1}},您无需再次添加。
答案 1 :(得分:45)
我将解释原始代码不起作用的原因。
在查找实例属性/方法时,Python需要决定搜索(直接和间接)基类的顺序。它通过线性化继承图来实现,即通过使用名为C3 or MRO的算法将基类图转换为序列。 MRO算法是一种独特的算法,可以实现几个理想的属性:
A
的孩子总是出现在班级B
的孩子面前,那么A
应该出现在B
之前(“一致的扩展优先顺序”)使用您的代码,第二个约束要求首先显示Enemy
;第三个约束要求Player
首先出现。由于无法满足所有约束,python会报告您的继承层次结构是非法的。
如果您在GameObject
中切换基类的顺序,那么您的代码将会起作用:
class GameObject(Enemy, Player):
pass
这不仅仅是技术细节。在某些(希望很少见)的情况下,如果在多个类中定义方法,您可能需要考虑应该使用哪个类来获取您调用的方法。您定义基类的顺序会影响此选择。
答案 2 :(得分:5)
您所写的内容是GameObject
同时为Player
和Enemy
。但是Enemy
已经是Player
。 MRO问题只是声明如果您在a
中有一个字段Player
,那么在GameObject
实例中询问此字段将是不明确的:它应该是来自a
的{{1}}您继承的第一个Player
或您通过Player
继承继承的Enemy
中的那个?
但是你确定你不想在这里使用合成而不是继承吗?
class GameObject(object):
def __init__(self):
self.player = Player()
self.enemy = Enemy()