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

这是我计划用于我的游戏的代码,但它抱怨一个 MRO 错误:

class Player:
pass


class Enemy(Player):
pass


class GameObject(Player, Enemy):
pass


g = GameObject()
104815 次浏览

你的 GameObject继承自 Player 还有 Enemy。因为 Enemy 已经继承自 Player Python 现在无法确定首先查找哪个类; Player或者 Enemy,后者将覆盖在 Player中定义的内容。

这里不需要命名 Enemy的所有基类; 只需继承这个类:

class GameObject(Enemy):
pass

Enemy已经包含了 Player,你不需要再包含它了。

你写的是你希望 GameObject既是 Player又是 Enemy。但是 Enemy已经是 Player了。MRO 问题只是指出,如果您在 Player中有一个字段 a,那么在 GameObject实例中请求这个字段将是模棱两可的: 它是来自您继承的第一个 Playera还是来自您通过 Enemy继承的 Playera

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

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

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

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

  1. 每个祖先类只出现一次
  2. 类总是出现在它的祖先之前(“单调性”)
  3. 同一类的直接父类应该按照类定义中列出的顺序出现(“一致的局部优先顺序”)
  4. 如果 A类的子类总是出现在 B类的子类之前,那么 A应该出现在 B类之前(“一致的扩展优先顺序”)

对于代码,第二个约束要求首先显示 Enemy; 第三个约束要求首先显示 Player。由于无法满足所有约束,因此 python 报告继承层次结构是非法的。

如果像下面这样切换 GameObject中基类的顺序,代码就可以工作了:

class GameObject(Enemy, Player):
pass

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