2015-03-23 5 views
26

Это код, который я планирую использовать для своей игры. Но он жалуется на ошибку MRO. Я не знаю почему. Может ли кто-то объяснить мне? Большое спасибо.TypeError: Невозможно создать согласованный порядок разрешения метода (MRO)

class Player: 
    pass 

class Enemy(Player): 
    pass 

class GameObject(Player, Enemy): 
    pass 

g = GameObject() 

ответ

53

Ваш GameObject наследуется от PlayerиEnemy. Потому что Enemyуже наследует от Player Python теперь не может определить, какой класс будет искать методы на первом; либо Player, либо на Enemy, что переопределит все, что определено в Player.

Здесь не обязательно указывать все базовые классы Enemy; просто наследоваться от этого одного класса:

class GameObject(Enemy): 
    pass 

Enemy уже включает в себя Player, вам не нужно, чтобы включить его снова.

4

Что вы написали, вы хотите, чтобы GameObject был как Player, так и Enemy. Но Enemy уже есть Player. Вопрос MRO просто утверждает, что если у вас есть поле a в Player, прося для этого поля в GameObject случае будет неоднозначным: оно должно быть a от первого Player вы унаследовать или один из Player вы унаследовали через Enemy наследства ?

Но вы уверены, что не хотите использовать композицию вместо наследования?

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

Я объясню причину, по которой исходный код не работает.

Python должен решить, в каком порядке искать базовые классы (прямые и косвенные) при поиске атрибута/метода экземпляра. Он делает это путем линеаризации графа наследования, то есть путем преобразования графика базовых классов в последовательность, используя алгоритм, называемый C3 or MRO. Алгоритм MRO является уникальный алгоритм, который достигает нескольких желательных свойств:

  1. каждый класс предок появляется ровно один раз
  2. класс всегда появляется перед его предка («монотонности»)
  3. прямые родители одного и того же класса должны появляюсь в том же порядке, в котором они перечислены в определении класса («соответствуют локальному порядку старшинства»)
  4. если дети класса A всегда появляются перед детьми класса B, то A должны предстать перед B («последовательным расширенным порядком старшинства»)

С кодом, для второго ограничения требуется, чтобы сначала появилось Enemy; третье ограничение требует, чтобы сначала появилось Player. Поскольку нет возможности удовлетворить все ограничения, отчеты python о том, что ваша иерархия наследования является незаконной.

Ваш код будет работать, если вы изменить порядок базовых классов в GameObject так:

class GameObject(Enemy, Player): 
    pass 

Это не просто техническая деталь. В некоторых (надеюсь, редких) случаях вам может понадобиться подумать о том, какой класс следует использовать для захвата метода, который вы вызывали, если метод определен в нескольких классах. На этот выбор влияет порядок, в котором вы определяете базовые классы.

+2

Это гораздо лучший ответ, чем принятый. –

Смежные вопросы