Cosa fa "mro ()"?


Risposte:


211

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.


9
ciao alex, c'è qualche differenza tra D .__ mro__ e D.mro ().
zjm1126,

26
mropuò 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/… .
Alex Martelli,

23
Perché si chiama ordine di risoluzione del metodo anziché ordine di risoluzione degli attributi ?
Bentley4,

1
Proprio come ha detto @Alex Martelli e il contenuto di python-history.blogspot.com/2010/06/… , l' attributo mro dovrebbe essere aggiunto quando viene utilizzata la nuova classe, come solo quando Python 2.2 MRO e Python 2.3 MRO (C3) sono usati.
andy,

82

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.


10

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.


1
Come puoi vedere, l'ordine è D, B, A, C
Stryker,

1
Cosa intendi con "Python rimuove la prima menzione di quella classe da mro"?
Ruthvik Vaila,

2
@RuthvikVaila: penso che la parte sia appena dichiarata male. In questo post sul blog sulla storia di Python, osserva Guido van Rossum (sullo schema MRO introdotto in Python 2.2) "Se una classe fosse duplicata in questa ricerca, tutti tranne l' ultima occorrenza verrebbero eliminati dall'elenco MRO" (sottolineatura mia ). Ciò implica che potrebbe rimuovere più di una semplice "menzione" della classe.
martineau,

1

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'>)

ma perché la risoluzione è diversa?
Vadim,

Nello scenario di ereditarietà multipla, qualsiasi attributo specificato viene cercato per primo nella classe corrente. Se non viene trovata, la ricerca continua nelle classi principali in modo approfondito, da sinistra a destra senza cercare due volte la stessa classe.
Girish Gupta,

scusa ma non capisco perché nel primo caso vada a finire class B3ma nel secondo caso vada class Adopoclass B1
Vadim
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.