MRO - Method Resolution Order

Linearizzazione del DAG delle superclassi

class D: pass
class E: pass
class A(D): pass
class B(E): pass
class C(A,D,B): pass
flowchart LR
	A --> D
	B --> E
	C --> A 
	C --> D 
	C --> B
	E --> object
	D --> object

Usando la funzione mro() su una di queste sottoclassi, come ad esempio C, viene restituita un array come il seguente:

[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class 'object'>]

Quindi per la ricerca degli attributi, il grafo è stato linearizzato come segue: [C, A, D, B, E, object].

ATTENZIONE

Non tutti i DAG possono essere linearizzati!

class B: pass
class A(object, B): pass

Genera errore, in quanto entrambe le classi, A e B puntano a object, e si verrebbe a creare un grafo del genere:

flowchart LR
	B --> object
	A --> object
	A --> B

Linearizzazione

In generale viene usato un metodo depth-first/left-to-right del DAG per risolverla.

MonotonicitĂ 

Se precede nella linearizzazione di C, allora questo avverrĂ  per la linearizzazione di tutte le sottoclassi di C.

Precedenza locale

L’ordine delle classi base della definizione di una classe, è preservato nella linearizzazione delle sottoclassi.

class D: pass 
class C(D): pass 
class B(C): pass
class G: pass
class F(G): pass
class E(F): pass
class J: pass
class I(J): pass
class H(I): pass
class A(B,E,H): pass

Le classi qui sopra si possono visualizzare meglio con un grafico:

graph BT
    A --> B
    A --> E
    A --> H
    B --> C
    C --> D
    E --> F
    F --> G
    H --> I
    I --> J
    D --> object
    G --> object
    J --> object

Algoritmo di linearizzazione

Terminologia:

  • grafo costituito da tutti e soli i vertici raggiungibili da S
  • linearizzazione di , rappresentata come una lista
  • linearizzazione di un generico , con testa e coda della linearizzazione
  1. Se la linearizzazione è composta da object. passo base della ricorsione. S è la classe sulla quale si linearizza, e sono le classi base di S.
  2. Si suppone che ricorsivamente siano giĂ  stati linearizzati i grafi delle classi base e le liste si indicano con .
  3. Oltre a quelle liste si considera sempre un’altra lista delle classi base della classe che stiamo considerando,
  4. Una volta che si hanno tutte le liste, si fa il merge di queste liste.
    1. Si inizializza la lista
    2. Le liste vengono analizzate da sinistra a destra un elemento alla volta. Per ogni elemento si possono eseguire due azioni:
      1. viene inserito in fondo alla lista .
        • Se non compare nella coda di nessuna lista con , , viene rimosso da tutte le liste, con indice maggiore della lista che stiamo valutando (), che lo contengono.
        • Si ricomincia il processo con la testa della prima lista non vuota tra quelle rimaste.
        • Se sono tutte vuote l’algoritmo termina con successo.
      2. viene temporaneamente scartato.
        • Se compare nella coda di una lista con , viene scartato perchè viola la regola di monotonicitĂ , dal momento che dovrebbe essere dopo . Per la stessa ragione non si possono inserire tutti i restanti elementi di .
        • Si cerca quindi la testa della prima lista non vuota di indice che non sia un elemento scartato. Se si arriva in fondo alle liste senza trovare un elemento inseribile la linearizzazione fallisce.

Esempio

class F: pass
class E: pass
class D: pass
class C(D,F): pass
class B(D,E): pass
class A(B,C): pass
    1. Si esegue il merge
      • B non compare in nessun’altra lista, quindi , e
      • D compare nella coda di , quindi bisogna passare a valutare la testa di
      • C non compare in nessun’altra lista, quindi , e
      • Ripartendo dalla prima lista, si ha D, che è in testa a tutte le liste, e quindi , e
      • E compare solo in , quindi e
      • O compare anche in , quindi si inserisce F e si ha , e
      • Si finisce con e tutte le altre listevuote.
title: Attenzione
La lista $B_i$ serve a evitare violazioni della regola di precedenza locale.
 
`class C: pass`
`class B(C): pass`
`class A(C, B): pass`
 
Avendo liste $CO$, $BCO$ e $CB$, si ha che il grafo non è linearizzabile.

python_book3