TypeError:无法创建一致的方法解析顺序(MRO)

时间:2015-03-23 16:04:28

标签: python inheritance typeerror method-resolution-order

这是我计划用于游戏的代码。但它抱怨MRO错误。我不知道为什么。有人能为我解释一下吗?非常感谢。

class Player:
    pass

class Enemy(Player):
    pass

class GameObject(Player, Enemy):
    pass

g = GameObject()

3 个答案:

答案 0 :(得分:85)

您的GameObject继承自Player Enemy。因为Enemy 已经继承自Player Python现在无法确定首先查找方法的类; PlayerEnemy上的Player,会覆盖Enemy中定义的内容。

您不需要在此处命名class GameObject(Enemy): pass 的所有基类;只从这一个类继承:

Enemy

Player已包含{{1}},您无需再次添加。

答案 1 :(得分:45)

我将解释原始代码不起作用的原因。

在查找实例属性/方法时,Python需要决定搜索(直接和间接)基类的顺序。它通过线性化继承图来实现,即通过使用名为C3 or MRO的算法将基类图转换为序列。 MRO算法是一种独特的算法,可以实现几个理想的属性:

  1. 每个祖先类只出现一次
  2. 一个班总是出现在它的祖先(“单调性”)
  3. 之前
  4. 同一类的直接父类应按照类定义中列出的顺序出现(“一致的本地优先顺序”)
  5. 如果班级A的孩子总是出现在班级B的孩子面前,那么A应该出现在B之前(“一致的扩展优先顺序”)
  6. 使用您的代码,第二个约束要求首先显示Enemy;第三个约束要求Player首先出现。由于无法满足所有约束,python会报告您的继承层次结构是非法的。

    如果您在GameObject中切换基类的顺序,那么您的代码将会起作用:

    class GameObject(Enemy, Player):
        pass
    

    这不仅仅是技术细节。在某些(希望很少见)的情况下,如果在多个类中定义方法,您可能需要考虑应该使用哪个类来获取您调用的方法。您定义基类的顺序会影响此选择。

答案 2 :(得分:5)

您所写的内容是GameObject同时为PlayerEnemy。但是Enemy已经是Player。 MRO问题只是声明如果您在a中有一个字段Player,那么在GameObject实例中询问此字段将是不明确的:它应该是来自a的{​​{1}}您继承的第一个Player或您通过Player继承继承的Enemy中的那个?

但是你确定你不想在这里使用合成而不是继承吗?

class GameObject(object):
    def __init__(self):
        self.player = Player()
        self.enemy = Enemy()