web-dev-qa-db-fra.com

TypeError: Impossible de créer un ordre de résolution de méthode cohérent (MRO)

C'est le code que je prévois d'utiliser pour mon jeu. Mais il se plaint d'une erreur de MRO. Je ne sais pas pourquoi. Quelqu'un peut m'expliquer? Merci beaucoup.

class Player:
    pass

class Enemy(Player):
    pass

class GameObject(Player, Enemy):
    pass

g = GameObject()
74
user188276

Votre GameObject hérite de Player et de Enemy. Parce que Enemy déjà hérite de Player Python ne peut pas maintenant déterminer la classe sur laquelle rechercher les méthodes; Player, ou sur Enemy, qui remplacerait les éléments définis dans Player.

Vous n'avez pas besoin de nommer toutes les classes de base de Enemy ici; juste hériter de cette classe:

class GameObject(Enemy):
    pass

Enemy inclut déjà Player, vous n'avez pas besoin de l'inclure à nouveau.

99
Martijn Pieters

Je vais expliquer la raison pour laquelle le code d'origine ne fonctionne pas.

Python doit décider dans quel ordre chercher dans les classes de base (directes et indirectes) lors de la recherche d'un attribut/méthode d'instance. Pour ce faire, il linéarise le graphe d'héritage, c'est-à-dire qu'il convertit le graphe des classes de base en une séquence, à l'aide d'un algorithme appelé C3 ou MRO . L'algorithme MRO est l'unique algorithme qui réalise plusieurs propriétés souhaitables:

  1. chaque classe d'ancêtre apparaît exactement une fois
  2. une classe apparaît toujours avant son ancêtre ("monotonicité")
  3. les parents directs de la même classe doivent apparaître dans le même ordre que dans la définition de la classe ("ordre de priorité local cohérent")
  4. si les enfants de la classe A apparaissent toujours avant les enfants de la classe B, alors A devrait apparaître avant B ("ordre de priorité étendu cohérent")

Avec votre code, la deuxième contrainte nécessite que Enemy apparaisse en premier; la troisième contrainte nécessite que Player apparaisse en premier. Comme il n’existe aucun moyen de satisfaire toutes les contraintes, python indique que votre hiérarchie d’héritage est illégale.

Votre code fonctionnera si vous changez l'ordre des classes de base dans GameObject comme ceci:

class GameObject(Enemy, Player):
    pass

Ce n'est pas juste un détail technique. Dans certains cas (espérons-le rares), vous voudrez peut-être déterminer quelle classe doit être utilisée pour récupérer la méthode que vous avez appelée si elle est définie dans plusieurs classes. L'ordre dans lequel vous définissez les classes de base affecte ce choix.

54
max

Ce que vous avez écrit, c'est que vous voulez que GameObject soit à la fois Player et Enemy. Mais un Enemy est déjà un Player. Le problème de MRO indique simplement que si vous aviez un champ a dans Player, demander ce champ dans une instance GameObject serait ambigu: ce devrait être le a du premier Player dont vous héritez ou celui du Player que vous héritez via votre héritage Enemy?

Mais êtes-vous sûr de ne pas vouloir utiliser la composition au lieu de l'héritage, ici?

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