Questo è dettagliato con una ragionevole quantità di dettagli dallo stesso Guido nel suo post sul metodo di risoluzione del metodo (inclusi due tentativi precedenti).
Nel tuo esempio, Third()
chiamerò First.__init__
. Python cerca ogni attributo nei genitori della classe in quanto sono elencati da sinistra a destra. In questo caso, stiamo cercando __init__
. Quindi, se lo definisci
class Third(First, Second):
...
Python inizierà guardando First
e, se First
non ha l'attributo, allora guarderà Second
.
Questa situazione diventa più complessa quando l'eredità inizia a incrociare percorsi (ad esempio se First
ereditati da Second
). Leggi il link sopra per maggiori dettagli, ma, in poche parole, Python proverà a mantenere l'ordine in cui ogni classe appare nell'elenco delle eredità, a partire dalla classe figlio stessa.
Quindi, ad esempio, se avessi:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
il MRO sarebbe [Fourth, Second, Third, First].
A proposito: se Python non riesce a trovare un ordine coerente di risoluzione del metodo, solleverà un'eccezione, invece di ricorrere a comportamenti che potrebbero sorprendere l'utente.
Modificato per aggiungere un esempio di MRO ambiguo:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Third
MRO dovrebbe essere [First, Second]
o [Second, First]
? Non ci sono aspettative ovvie e Python genererà un errore:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
Modifica: vedo diverse persone che sostengono che gli esempi sopra mancano di super()
chiamate, quindi lasciami spiegare: il punto degli esempi è mostrare come è costruito l'MRO. Essi sono non intendono stampare "prima \ nsecond \ terzo" o qualsiasi altra cosa. Puoi - e dovresti, naturalmente, giocare con l'esempio, aggiungere super()
chiamate, vedere cosa succede e ottenere una comprensione più profonda del modello di eredità di Python. Ma il mio obiettivo qui è quello di renderlo semplice e mostrare come è costruito l'MRO. Ed è costruito come ho spiegato:
>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)
super()
è utile. Non consiglierei di usarlo con le classi usando l'eredità lineare, dove è solo inutile sovraccarico.