L'attributo __mro__ in Python

L'attributo `__mro__` (Method Resolution Order) è una tupla che indica l'ordine in cui Python cerca i metodi e gli attributi nelle classi coinvolte nella gerarchia di ereditarietà.

classe.__mro__

In altre parole, se hai una classe che eredita da altre classi, `__mro__` ti dice in quale ordine Python visiterà queste classi per trovare un metodo o un attributo.

Perché è importante? Capire l'ordine di risoluzione dei metodi è cruciale quando lavori con l'ereditarietà multipla in Python, perché ti aiuta a prevedere quale metodo verrà chiamato. Questo può prevenire comportamenti inattesi e bug difficili da individuare.

Ecco un esempio semplice per vedere cpme funziona in pratica

Immagina di avere una semplice gerarchia di classi:

class A:
   def method(self):
      return "Method in A"

class B(A):
   def method(self):
      return "Method in B"

class C(A):
    def method(self):
      return "Method in C"

class D(B, C):
    pass

In questo esempio, `D` eredita da `B` e `C`, che a loro volta ereditano da `A`.

Vediamo cosa ci dice `__mro__`:

print(D.__mro__)

L'output sarà:

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

Questo significa che se chiami il metodo `method` su un'istanza di `D`, Python cercherà il metodo in quest'ordine:

  1. Classe `D`
  2. Classe `B`
  3. Classe `C`
  4. Classe `A`
  5. Classe `object` (la classe base di tutte le classi in Python)

Ad esempio, prova a creare un'istanza della classe D.

d = D()

Poi, chiama il metodo

print(d.method())

L'output sarà:

Method in B

Python ha trovato il metodo `method` in `B` prima di `C`, quindi ha chiamato quello.

Nell'ordine di risoluzione dei metodi Python cerca il metodo da eseguire seguendo l'ordine presente nell'attributo MRO. Se non lo trova in una classe, lo cerca in quella gerarchicamente inferiore.

Cosa succede se cambi l'ordine delle classi base di `D`?

Facciamo una prova, modifica l'ereditarietà

class A:
   def method(self):
      return "Method in A"

class B(A):
   def method(self):
      return "Method in B"

class C(A):
    def method(self):
      return "Method in C"

class D(C,B ):
    pass

Ora classe D eredita prima da C e poi da B.

print(D.__mro__)

(<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

Crea di nuovo un'istanza della classe D

d = D()

Poi, chiama il metodo

print(d.method())

Method in C

Anche questa volta Python segue l'ordine di risoluzione e trova `method` in `C` prima di `B`.

Python usa un algoritmo chiamato C3 Linearization per determinare l'ordine di risoluzione dei metodi. Questo algoritmo garantisce che l'ordine di risoluzione dei metodi sia deterministico e rispetti le regole di ereditarietà di Python.

Spero che questa guida ti abbia aiutato a comprendere meglio l'attributo `__mro__` e come usarlo nei tuoi progetti Python. 

 




Se qualcosa non ti è chiaro, scrivi la tua domanda nei commenti.




FacebookTwitterLinkedinLinkedin