Подтвердить что ты не робот

TypeError: невозможно создать согласованный порядок разрешения метода (MRO)

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

class Player:
    pass

class Enemy(Player):
    pass

class GameObject(Player, Enemy):
    pass

g = GameObject()
4b9b3361

Ответ 1

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

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

class GameObject(Enemy):
    pass

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

Ответ 2

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

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

  • каждый класс предков появляется ровно один раз
  • класс всегда появляется перед его предком ( "монотонность" )
  • прямые родители того же класса должны отображаться в том же порядке, в каком они указаны в определении класса ( "согласованный локальный порядок приоритета" )
  • если дети класса A всегда появляются перед дочерними элементами класса B, тогда A должен появиться перед B ( "согласованный расширенный порядок приоритета" )

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

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

class GameObject(Enemy, Player):
    pass

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

Ответ 3

То, что вы написали, - это то, что вы хотите, чтобы 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()