Nel tutorial del pitone si dice che "Python supports a limited form of multiple inheritance".Python supporta una forma limitata di ereditarietà multipla. In che modo limitato?
Quali sono le limitazioni?
Nel tutorial del pitone si dice che "Python supports a limited form of multiple inheritance".Python supporta una forma limitata di ereditarietà multipla. In che modo limitato?
Quali sono le limitazioni?
Oltre alla risposta di @Matt Anderson, penso che le limitazioni siano in effetti per le classi di vecchio stile (che è il tutorial per Python 2.6 still addresses).
Nel tutorial Python 3 il testo è ora: Python supports a form of multiple inheritance as well.
Non sono sicuro di quali limitazioni si riferiva l'autore del tutorial su Python, ma suppongo che abbia in parte a che fare con il metodo di ricerca degli attributi in Python (il "metodo di risoluzione") o MRO). Python usa il meccanismo C3 superclass linearization; questo è quello di trattare quello che viene definito "The Diamond Problem".
Dopo aver introdotto l'ereditarietà multipla nella gerarchia di classi, qualsiasi classe data non ha una singola classe potenziale da cui eredita, ha solo "la prossima classe nell'MRO", anche per le classi che si aspettano che loro ereditano da una classe in particolare.
Per esempio, se class A(object)
, class B(A)
, class C(A)
, e class D(B, C)
, poi la MRO per la classe D
è D->B->C->A
. La Classe B potrebbe essere stata scritta, probabilmente lo era, pensando che discenda da A, e quando chiama lo super()
su se stesso, otterrà un metodo su A. Ma questo non è più vero; quando B chiama super()
, otterrà invece un metodo su C, se esiste.
Se si modificano le firme del metodo in metodi sovrascritti, ciò può rappresentare un problema. La classe B, che prevede la firma di un metodo dalla classe A quando chiama super, ottiene invece un metodo da C, che potrebbe non avere quella firma (e potrebbe o meno non implementare il comportamento desiderato, dal punto di vista della classe B).
class A(object):
def __init__(self, foo):
print "A!"
class B(A):
def __init__(self, foo, bar):
print "B!"
super(B, self).__init__(foo)
class C(A):
def __init__(self, foo, baaz):
print "C!"
super(C, self).__init__(foo)
class D(B, C):
def __init__(self, foo, bar):
print "D!"
super(D, self).__init__(foo, bar)
print D.mro()
D("foo", "bar")
In questo esempio di codice, classi B e C hanno ragionevolmente esteso A, e cambiato le loro __init__
firme, ma chiamare correttamente la loro firma superclasse previsto. Ma quando si effettua D così, la "superclasse" efficace di B diventa C invece di A. Quando si chiama super, le cose saltare in aria:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>]
D!
B!
Traceback (most recent call last):
File "/tmp/multi_inherit.py", line 22, in <module>
D("foo", "bar")
File "/tmp/multi_inherit.py", line 19, in __init__
super(D, self).__init__(foo, bar)
File "/tmp/multi_inherit.py", line 9, in __init__
super(B, self).__init__(foo)
TypeError: __init__() takes exactly 3 arguments (2 given)
Questa stessa cosa potrebbe accadere per altri metodi, come pure (se chiamano super()
) e il "diamante" non deve apparire solo nella radice della gerarchia di classi.
Tutto ciò è vero, ma qualsiasi lingua con eredità multipla deve affrontare questi problemi. Se riteniamo che la tua risposta sia corretta, allora quale linguaggio (con MI) * non avrebbe * una forma limitata di ereditarietà multipla? –