In questo tutorial impareremo l'ordine di risoluzione dei metodi, noto anche come MRO. È un concetto essenziale dell'ereditarietà Python.
L'ordine di risoluzione del metodo descrive il percorso di ricerca della classe which Pitone utilizza per ottenere il metodo appropriato nelle classi che contengono l'ereditarietà multipla.
introduzione
Come sappiamo, una classe che viene ereditata è chiamata sottoclasse o classe genitore, mentre la classe che eredita è conosciuta come classe figlia o sottoclasse. Nell'ereditarietà multipla, una classe può essere costituita da molte funzioni, quindi la tecnica dell'ordine di risoluzione del metodo viene utilizzata per cercare l'ordine in cui viene eseguita la classe base.
imbottitura np
In parole semplici: 'Il metodo o gli attributi vengono esplorati nella classe corrente, se il metodo non è presente nella classe corrente, la ricerca si sposta nelle classi genitori e così via'. Questo è un esempio di ricerca approfondita.
Svolge un ruolo essenziale nell'ereditarietà multipla in cui lo stesso metodo può essere trovato in più superclassi.
Per capirlo meglio, vediamo come possiamo usarlo.
Esempio -
class A: def myname(self): print('I am a class A') class B(A): def myname(self): print('I am a class B') class C(A): def myname(self): print('I am a class C') c = C() print(c.myname())
Produzione:
I am a class C
Spiegazione -
C'è un'ereditarietà multipla nel codice sopra. Abbiamo definito tre classi chiamate A, B e C e queste classi hanno lo stesso nome chiamato metodo il mio nome(). Abbiamo creato un oggetto di classe C. L'oggetto invocava la classe C, non la classe, mentre la classe C ereditava il metodo della classe A.
L'ordine da seguire nel codice sopra è classe B -> classe A. Questa tecnica è nota come MRO (metodo di risoluzione ordine).
Comprendiamo un altro esempio di ereditarietà multipla.
Esempio -
class A: def myname(self): print(' I am a class A') class B(A): def myname(self): print(' I am a class B') class C(A): def myname(self): print('I am a class C') # classes ordering class D(B, C): pass d = D() d.myname()
Produzione:
I am a class B
Spiegazione -
Nel codice precedente, abbiamo creato un'altra classe D senza definire gli attributi di classe che ereditavano le classi B e C. Quando abbiamo invocato il metodo il mio nome(), va alla classe D e cerca il il mio nome( ) funzione. Ma la classe D non ha alcuna dichiarazione. Quindi, la ricerca viene trasferita alla classe B, ottiene il file il mio nome() funzione e restituisce il risultato. La ricerca si svolgerà come segue.
Class D -> Class B -> Class C -> Class A
Se la classe B non avesse un metodo, invocherà il metodo della classe C.
Qui, ti suggeriamo di rimuovere il metodo di classe B e verificare cosa succede. In questo modo, avrai un'idea di come funziona la risoluzione del metodo.
Ordine di vecchio e nuovo stile
Nella versione precedente di Python (2.1), siamo limitati a utilizzare le vecchie classi ma Pitone (2.2 e continua), possiamo usare le nuove classi. Per impostazione predefinita, Python 3 ha classi originali (nuove). Il primo genitore della nuova classe di stile eredita dalla classe 'oggetto' root di Python. Vediamo il seguente esempio -
Esempio -
# Old style class class OldStyleClass: pass # New style class class NewStyleClass(object): pass
Lo stile della dichiarazione di entrambe le classi è diverso. Nella risoluzione del metodo, le classi vecchio stile seguono l'algoritmo DLR (profondità prima da sinistra a destra), mentre le nuove classi di stile utilizzano l'algoritmo di linearizzazione C3 durante l'esecuzione dell'ereditarietà multipla.
matrice di stringhe c
Algoritmo DLR
Python crea un elenco di classi mentre implementa l'ereditarietà multipla tra le classi. Tale elenco viene utilizzato per determinare quale metodo deve essere chiamato quando viene invocato dalle istanze.
Possiamo supporre che funzioni con il suo nome poiché la risoluzione del metodo effettuerà prima la ricerca in profondità, quindi andrà da sinistra a destra. Di seguito è riportato l'esempio.
Esempio -
class A: pass class B: pass class C(A, B): pass class D(B, A): pass class E(C,D): pass
Innanzitutto, l'algoritmo cercherà nella classe dell'istanza il metodo invocato. Se non viene trovato, passa ai primi genitori, se non viene trovato nemmeno lì. Esaminerà il genitore del genitore. Ciò continuerà fino alla fine delle classi ereditarie.
Nell'esempio precedente, l'ordine di risoluzione del metodo sarà:
class D -> class B -> class A -> class C -> class A
Ma A non può essere presente due volte, quindi...
class D -> class B -> class A -> class C ->
Questo algoritmo mostra lo strano comportamento in quel momento. Vediamo l'esempio qui sotto.
Esempio -
class A: pass class B: pass class C(A, B): pass class D(B, A): pass class E(C,D): pass
Secondo l'algoritmo DLR, l'ordine sarà E, C, D, B, A. C'è lo scambio delle classi A e B nella classe C, il che è molto ambiguo. Ciò significa che l'algoritmo non preserva la proprietà di monotonicità.
Samuele Perdoni è stato il primo a scoprire un'incoerenza tra gli algoritmi MRO.
Algoritmo di linearizzazione C3
L'algoritmo di linearizzazione C3 è una versione migliore dell'algoritmo DLR perché rimuove l'incoerenza. Questo algoritmo presenta alcune restrizioni riportate di seguito.
- I figli devono precedere i genitori.
- Se una classe particolare eredita da una o più classi, queste vengono salvate nell'ordine specificato nella tupla della classe base.
Regole dell'algoritmo di linearizzazione C3
- La struttura dell'ordine di risoluzione del metodo è definita dal grafico dell'ereditarietà.
- L'utente deve visitare la super classe solo dopo aver visitato i metodi delle classi locali.
- Preservare la monotonia
Metodo per la classe di risoluzione del metodo
Python fornisce due modi per ottenere l'ordine di risoluzione del metodo di una classe: __mro__ attributo o mro() metodo. Con l'aiuto di questi metodi possiamo visualizzare l'ordine del metodo in cui vengono risolti.
Comprendiamo il seguente esempio.
data dattiloscritta
Esempio -
class A: def myname(self): print(' I am a class A') class B(A): def myname(self): print(' I am a class B') class C(A): def myname(self): print('I am a class C') # classes ordering class D(B, C): pass # it prints the lookup order print(D.__mro__) print(C.mro())
Produzione:
(, , , , ) [, , ]
Come possiamo vedere nell'output sopra, otteniamo l'ordine di risoluzione del metodo. In questo modo, l'algoritmo di linearizzazione C3 funziona per l'ereditarietà multipla.