Python 类型错误:无法创建一致的方法解析顺序 (MRO)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29214888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 04:12:45  来源:igfitidea点击:

TypeError: Cannot create a consistent method resolution order (MRO)

pythoninheritancetypeerrormethod-resolution-order

提问by

This is the code which I plan to use for my game, but it complains about an MRO error:

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

class Player:
    pass

class Enemy(Player):
    pass

class GameObject(Player, Enemy):
    pass

g = GameObject()

采纳答案by Martijn Pieters

Your GameObjectis inheriting from PlayerandEnemy. Because Enemyalreadyinherits from PlayerPython now cannot determine what class to look methods up on first; either Player, or on Enemy, which would override things defined in Player.

GameObject继承自PlayerEnemy。因为Enemy已经继承自PlayerPython 现在无法确定首先查找哪个类;要么Player,或者Enemy,这将覆盖定义的东西Player

You don't need to name all base classes of Enemyhere; just inherit from that one class:

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

class GameObject(Enemy):
    pass

Enemyalready includes Player, you don't need to include it again.

Enemy已经包含Player,您不需要再次包含它。

回答by Francis Colas

What you wrote is you want a GameObjectto be both a Playerand an Enemy. But an Enemyis already a Player. The MRO issue just states that if you had a field ain Player, asking for this field in a GameObjectinstance would be ambiguous: should it be the afrom the first Playeryou inherit or the one from the Playeryou inherit through your Enemyinheritance?

你写的是你想要 aGameObject既是 aPlayer又是Enemy。但是 anEnemy已经是一个Player. 该MRO问题只是指出,如果你有一个领域aPlayer,要求这个领域的GameObject实例将是不明确的:它应该是a从第一个Player你继承,或从一个Player你通过继承Enemy遗产?

But are you sure you don't want to use composition instead of inheritance, here?

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

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

回答by max

I'll explain the reason the original code doesn't work.

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

Python needs to decide in which order to search through (direct and indirect) base classes when looking up an instance attribute / method. It does this by linearizing the inheritance graph, that is by converting the graph of base classes into a sequence, using an algorithm called C3 or MRO. The MRO algorithm is the unique algorithm that achieves several desirable properties:

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

  1. each ancestor class appears exactly once
  2. a class always appears before its ancestor ("monotonicity")
  3. direct parents of the same class should appear in the same order as they are listed in class definition ("consistent local precedence order")
  4. if children of class Aalways appear before children of class B, then Ashould appear before B("consistent extended precedence order")
  1. 每个祖先类只出现一次
  2. 一个类总是出现在它的祖先之前(“单调性”)
  3. 同一个类的直接父类应该按照它们在类定义中列出的顺序出现(“一致的本地优先顺序”)
  4. 如果 class 的孩子A总是出现在 class 的孩子之前B,那么A应该出现在之前B(“一致的扩展优先顺序”)

With your code, the second constraint requires that Enemyappears first; the third constraint requires that Playerappears first. Since there's no way to satisfy all constraints, python reports that your inheritance hierarchy is illegal.

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

Your code will work if you switch the order of base classes in GameObjectlike so:

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

class GameObject(Enemy, Player):
    pass

This is not just a technical detail. In some (hopefully rare) cases, you might want to think about which class should be used to grab the method you called if the method is defined in multiple classes. The order in which you define base classes affects this choice.

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