【问题标题】:TypeError: Cannot create a consistent method resolution order (MRO) [duplicate]TypeError:无法创建一致的方法解析顺序(MRO)[重复]
【发布时间】:2020-09-10 14:05:36
【问题描述】:

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

class Player:
    pass

class Enemy(Player):
    pass

class GameObject(Player, Enemy):
    pass

g = GameObject()

【问题讨论】:

    标签: python inheritance typeerror method-resolution-order


    【解决方案1】:

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

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

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

    使用您的代码,第二个约束要求Enemy 首先出现;第三个约束要求Player 首先出现。由于无法满足所有约束,python 报告您的继承层次结构是非法的。

    如果您像这样切换GameObject 中基类的顺序,您的代码将起作用:

    class GameObject(Enemy, Player):
        pass
    

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

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

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

        class GameObject(Enemy):
            pass
        

        Enemy 已包含Player,您无需再次包含它。

        【讨论】:

          猜你喜欢
          • 2019-01-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多