这是我计划在游戏中使用的代码,但它抱怨MRO错误:
class Player:
pass
class Enemy(Player):
pass
class GameObject(Player, Enemy):
pass
g = GameObject()
您的GameObject
继承自Player
和Enemy
。因为Enemy
已经继承自Player
Python现在无法确定首先查找方法的类;Player
或Enemy
,这将覆盖Player
中定义的内容。
您不需要在这里命名Enemy
的所有基类;只需继承一个类:
class GameObject(Enemy):
pass
Enemy
已经包含Player
,您不需要再包含它。
我将解释原始代码不起作用的原因。
在查找实例属性/方法时,Python需要决定搜索(直接和间接)基类的顺序。它通过线性化继承图来实现这一点,也就是说,使用一种称为C3或MRO的算法,将基类的图转换为序列。MRO算法是一种独特的算法,它实现了几个理想的特性:
- 每个祖先类只出现一次
- 类总是出现在其祖先之前("单调性")
- 同一类的直接父类应按照类定义中列出的顺序出现("一致的局部优先顺序")
- 如果类
A
的子级总是出现在类B
的子级之前,则A
应该出现在B
之前("一致的扩展优先级顺序")
对于您的代码,第二个约束要求Enemy
首先出现;第三个约束要求CCD_ 17首先出现。由于无法满足所有约束,python报告您的继承层次结构是非法的。
如果你像这样切换GameObject
中基类的顺序,你的代码就会工作:
class GameObject(Enemy, Player):
pass
这不仅仅是一个技术细节。在某些情况下(希望是罕见的),如果方法在多个类中定义,您可能需要考虑应该使用哪个类来获取您调用的方法。定义基类的顺序会影响此选择。
您所写的是希望GameObject
既是Player
又是Enemy
。但是CCD_ 22已经是CCD_。MRO问题只是指出,如果您在Player
中有一个字段a
,那么在GameObject
实例中请求该字段将是不明确的:它是您继承的第一个Player
中的a
,还是您通过Enemy
继承的Player
中的CCD27?
但是你确定你不想使用组合而不是继承吗?
class GameObject(object):
def __init__(self):
self.player = Player()
self.enemy = Enemy()