lettura simple

L'ereditarietà multipla delle classi e l'ordine dei metodi in Python

L'ereditarietà multipla e l'ordine di risoluzione dei metodi (MRO) sono concetti cruciali per comprendere il comportamento delle classi in Python quando una classe eredita da più classi base.

  • Ereditarietà multipla
    Python supporta l'ereditarietà multipla, il che significa che una classe può ereditare da più classi base.
  • Ordine di risoluzione dei metordi (MRO)
    L'MRO (Method Resolution Order) definisce l'ordine con cui vengono cercati gli attributi e i metodi. L'MRO è disponibile attraverso l'attributo `__mro__`:

In altre parole l'ereditarietà multipla e l'MRO permettono a Python di risolvere in modo coerente quale metodo chiamare quando più classi base hanno metodi con lo stesso nome.

Vediamo di chiarire questi concetti con qualche esempio pratico.

Consideriamo il seguente esempio:

class A:
   a = 'alpha'
class B:
   b = 'beta'
class C:
   c = 'gamma'
class D(A, B, C):
   pass

In questo codice la classe `D` eredita dagli attributi delle classi `A`, `B` e `C`.

Crea un'istanza della classe D

d = D()

Ora se interroghi gli attributi `a`, `b`, `c` dall'istanza, l'oggetto restituisce i valori degli attributi delle classi originarie.

print(d.a, d.b, d.c)

alfa beta gamma

Gli attributi `__base__` e `__bases__`

Questi due attributi ti consentono di vedere quali sono le classi base da cui una classe eredita i metodi e gli attributi.

L'attributo `__base__` restituisce la prima classe base nell'ordine dell'ereditarietà multipla.

Nel caso della classe D, la prima classe base è la classe A.

print(D.__base__)

<class '__main__.A'>

L'attributo `__bases__` invece restituisce tutte le classi base di una classe.

Ad esempio, se lo interroghi sulla classe D, restituisce una tupla contenente le classi base A, B, C da cui eredita.

print(D.__bases__)

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

La funzione super() nell'ereditarietà multipla

La funzione super() ti permette di creare un'istanza che delega le chiamate dei metodi alla classe base successiva seguendo l'ordine definito dal MRO.

Consideriamo il seguente esempio:

class A:
   def foo(self):
       print('Hello')
class B:
   def foo(self):
       print('Hi')
class C:
   def foo(self):
      print('Hey')
class D(A, B, C):
   def foo(self):
     super().foo()

In questo caso la classe D chiama il metodo `foo` della prima classe base A nell'ordine di risoluzione dei metodi (MRO).

Ad esempio, crea un'istanza della classe D

d = D()

Ora se chiami il metodo d.foo() dall'istanza, questo restituisce in output "hello" ovvero il risultato del metodo foo() della classe A.

d.foo()

hello

Questo accade perché la prima classe base nell'ordine MRO della classe D è la classe A.

Method Resolution Order (MRO)

L'ordine di risoluzione dei metodi (MRO)  definisce l'ordine con cui Python cerca gli attributi e i metodi nelle classi base.

Puoi consultarlo tramite l'attributo `__mro__`

Ad esempio, definisci queste classi

class A:
   pass
class B:
   def foo(self):
       print('Hi')
class C:
   def foo(self):
      print('Hey')
class D(A, B, C):
   pass

La classe D eredita gli attributi e i metodi dalle classi base A, B, C esattamente in quest'ordine.

Ora crea un oggetto della classe D.

d=D()

Se interroghi l'attributo '__mro__', questo ti restituisce l'ordine di risoluzione dei metodi della classe D.

print(D.__mro__)

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

Questo risultato ti dice che la classe D risolve i metodi prima cercando in se stessa, poi nella classe A, nella classe B e infine nella classe C.

Quando chiami il metodo `d.foo()`, Python segue l'ordine dell'MRO.

d.foo()

Hi

In questo caso Python non trova la funzione foo() nella classe D, quindi la ricerca nella prima classe base nell'ordine MRO ovvero nella classe A.

Poiché non trova il metodo foo() nemmeno nella classe A, lo cerca nella classe B e lo esegue.

Se il metodo `foo` non fosse stato trovato in nessuna di queste classi, Python avrebbe sollevato un'eccezione AttributeError.




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




FacebookTwitterLinkedinLinkedin