Risposte:
Segui ...
>>> class A(object): pass
...
>>> A.__mro__
(<class '__main__.A'>, <type 'object'>)
>>> class B(A): pass
...
>>> B.__mro__
(<class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
>>> class C(A): pass
...
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
>>>
Finché abbiamo un'unica eredità, __mro__
è solo la tupla di: la classe, la sua base, la sua base di base e così via fino aobject
(funziona solo per le classi di nuovo stile ovviamente).
Ora, con eredità multipla ...:
>>> class D(B, C): pass
...
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
... hai anche la certezza che, in __mro__
, nessuna classe è duplicata e nessuna classe viene dopo i suoi antenati, salvo che le classi che per prime entrano nello stesso livello di eredità multipla (come B e C in questo esempio) sono nel __mro__
da sinistra a destra.
Ogni attributo che ottieni sull'istanza di una classe, non solo sui metodi, è concettualmente cercato lungo il __mro__
, quindi, se più di una classe tra gli antenati definisce quel nome, questo ti dice dove si troverà l'attributo - nella prima classe in quello __mro__
che definisce quel nome.
mro
può essere personalizzato da una metaclasse, viene chiamato una volta all'inizializzazione della classe e il risultato viene memorizzato in __mro__
- consultare docs.python.org/library/… .
mro()
è l'acronimo di Method Resolution Order. Restituisce un elenco di tipi da cui deriva la classe, nell'ordine in cui vengono cercati i metodi.
mro () o __mro__ funziona solo su nuove classi di stile. In Python 3 funzionano senza problemi. Ma in Python 2 quelle classi devono ereditare object
.
Ciò potrebbe forse mostrare l'ordine di risoluzione.
class A(object):
def dothis(self):
print('I am from A class')
class B(A):
pass
class C(object):
def dothis(self):
print('I am from C class')
class D(B, C):
pass
d_instance= D()
d_instance.dothis()
print(D.mro())
e la risposta sarebbe
I am from A class
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>]
La regola è la prima in profondità, che in questo caso significherebbe D, B, A, C.
Python normalmente usa un ordine di profondità per la ricerca delle classi ereditarie, ma quando due classi ereditano dalla stessa classe, Python rimuove la prima menzione di quella classe da mro.
L'ordine di risoluzione sarà diverso nell'eredità dei diamanti.
class A(object):
def dothis(self):
print('I am from A class')
class B1(A):
def dothis(self):
print('I am from B1 class')
# pass
class B2(object):
def dothis(self):
print('I am from B2 class')
# pass
class B3(A):
def dothis(self):
print('I am from B3 class')
# Diamond inheritance
class D1(B1, B3):
pass
class D2(B1, B2):
pass
d1_instance = D1()
d1_instance.dothis()
# I am from B1 class
print(D1.__mro__)
# (<class '__main__.D1'>, <class '__main__.B1'>, <class '__main__.B3'>, <class '__main__.A'>, <class 'object'>)
d2_instance = D2()
d2_instance.dothis()
# I am from B1 class
print(D2.__mro__)
# (<class '__main__.D2'>, <class '__main__.B1'>, <class '__main__.A'>, <class '__main__.B2'>, <class 'object'>)
class B3
ma nel secondo caso vada class A
dopoclass B1