python - TypeError: no se puede crear un orden de resolución de método(MRO) coherente
inheritance method-resolution-order (3)
Este es el código que planeo usar para mi juego. Pero se queja por un error MRO. No se porque. ¿Alguien puede explicar por mí? Muchas gracias.
class Player:
pass
class Enemy(Player):
pass
class GameObject(Player, Enemy):
pass
g = GameObject()
Explicaré la razón por la cual el código original no funciona.
Python necesita decidir en qué orden buscar a través de las clases base (directas e indirectas) al buscar un atributo / método de instancia. Para ello, linealiza el gráfico de herencia, es decir, convierte el gráfico de clases base en una secuencia, utilizando un algoritmo llamado C3 o MRO . El algoritmo MRO es el algoritmo único que logra varias propiedades deseables:
- cada clase de antepasado aparece exactamente una vez
- una clase siempre aparece antes de su antepasado ("monotonicidad")
- los padres directos de la misma clase deben aparecer en el mismo orden en que aparecen en la definición de clase ("orden de precedencia local coherente")
-
si los hijos de la clase
A
siempre aparecen antes que los hijos de la claseB
, entoncesA
debería aparecer antes queB
("orden de precedencia extendida consistente")
Con su código, la segunda restricción requiere que el
Enemy
aparezca primero;
La tercera restricción requiere que el
Player
aparezca primero.
Como no hay forma de satisfacer todas las restricciones, python informa que su jerarquía de herencia es ilegal.
Su código funcionará si cambia el orden de las clases base en
GameObject
así:
class GameObject(Enemy, Player):
pass
Esto no es solo un detalle técnico. En algunos casos (con suerte raros), es posible que desee pensar en qué clase se debe utilizar para obtener el método que llamó si el método se define en varias clases. El orden en el que define las clases base afecta esta elección.
Lo que escribiste es que quieres que un
GameObject
sea un
Player
y un
Enemy
.
Pero un
Enemy
ya es un
Player
.
El problema de MRO solo indica que si tuvieras un campo
a
en
Player
, pedir este campo en una instancia de
GameObject
sería ambiguo: si se trata del
a
del primer
Player
que heredas o el del
Player
que heredas a través de tu herencia
Enemy
?
Pero, ¿estás seguro de que no quieres usar composición en lugar de herencia, aquí?
class GameObject(object):
def __init__(self):
self.player = Player()
self.enemy = Enemy()
Su
GameObject
está heredando de
Player
y
Enemy
.
Debido a que
Enemy
ya
hereda de
Player
Python, ahora no puede determinar en qué clase buscar primero los métodos;
ya sea
Player
o en
Enemy
, lo que anularía las cosas definidas en
Player
.
No necesita nombrar todas las clases base de
Enemy
aquí;
simplemente hereda de esa clase:
class GameObject(Enemy):
pass
Enemy
ya incluye
Player
, no necesitas volver a incluirlo.