Spiegherò il motivo per cui il codice originale non funziona.
Python deve decidere in quale ordine cercare tra classi di base (dirette e indirette) durante la ricerca di un attributo/metodo di istanza. Lo fa linearizzando il grafico dell'ereditarietà, ovvero convertendo il grafico delle classi base in una sequenza, utilizzando un algoritmo chiamato C3 or MRO. L'algoritmo MRO è l'unico algoritmo che consente di ottenere diverse proprietà desiderabili:
- ogni classe antenato appare esattamente una volta
- una classe appare sempre prima della sua antenata ("monotonia")
- genitori diretti della stessa classe dovrebbe apparire nello stesso ordine in cui sono elencati nella definizione della classe ("consistente ordine di precedenza locale")
- se i bambini della classe
A
appaiono sempre prima che i bambini della classe B
, quindi A
dovrebbe comparire davanti B
("consistente ordine di precedenza esteso")
Con il proprio codice, il secondo vincolo richiede che venga visualizzato prima Enemy
; il terzo vincolo richiede che venga visualizzato per primo Player
. Poiché non c'è modo di soddisfare tutti i vincoli, python segnala che la gerarchia dell'ereditarietà è illegale.
Il codice funziona se si cambia l'ordine delle classi di base in GameObject
in questo modo:
class GameObject(Enemy, Player):
pass
Questo non è solo un dettaglio tecnico. In alcuni casi (si spera raramente), potresti voler pensare a quale classe dovrebbe essere usata per prendere il metodo che hai chiamato se il metodo è definito in più classi. L'ordine in cui vengono definite le classi di base influisce su questa scelta.
Questa è una risposta molto migliore di quella accettata. –