2010-01-06 8 views
91

In django.utils.functional.py:Was macht "mro()"?

for t in type(res).mro(): # <----- this 
    if t in self.__dispatch: 
     return self.__dispatch[t][funcname](res, *args, **kw) 

Ich verstehe nicht mro(). Was macht es und was bedeutet "mro"?

+2

http://www.python.org/download/releases/2.3/mro – GodMan

+1

Ooph, was für eine lange Lese das ist. – paulmelnikow

Antwort

164

Folgen entlang ...:

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

Solange wir einzelne Erbe haben, ist __mro__ nur das Tupel aus: die Klasse, seine Basis, Basis seiner Basis ist, und so weiter bis zu object (nur funktioniert natürlich auch für neue Klassen.

Jetzt, mit mehrere Erbe ...:

>>> class D(B, C): pass 
... 
>>> D.__mro__ 
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>) 

... Sie erhalten auch die Gewissheit, dass in __mro__ wird keine Klasse dupliziert, und keine Klasse kommt nach seinen Vorfahren, außer daß Klassen, die zuerst auf der gleichen Ebene der Mehrfachvererbung eintreten (wie B und C in diesem Beispiel), sind in der __mro__ von links nach rechts.

Jedes Attribut, das Sie für eine Klasseninstanz erhalten, nicht nur Methoden, wird konzeptuell entlang der __mro__ gesucht. Wenn also mehr als eine Klasse unter den Vorfahren diesen Namen definiert, sagt dies Ihnen, wo das Attribut gefunden wird - in der ersten Klasse in __mro__, die diesen Namen definiert.

+7

Hallo, Alex, gibt es einen Unterschied zwischen D.__mro__ und D.mro(). – zjm1126

+19

'mro' kann durch eine Metaklasse angepasst werden, wird in' __mro__' einmal bei Klasseninitialisierung und das Ergebnis gespeichert genannt wird - siehe http://docs.python.org/library/stdtypes.html?highlight=mro# Klasse .__ mro__. –

+13

Warum heißt es ** Methodenauflösungsreihenfolge ** statt ** Attributauflösungsreihenfolge **? – Bentley4

69

mro() steht für Methode Auflösung bestellen. Sie gibt eine Liste der Typen zurück, aus denen die Klasse abgeleitet ist, in der Reihenfolge, in der sie nach Methoden durchsucht werden.

MRO() oder __mro__ nur auf neue Art Klassen funktioniert. In Python 3 funktionieren sie ohne Probleme. Aber in Python 2 müssen diese Klassen von Objekten erben.

7

zeigen Dies würde vielleicht die Reihenfolge der Auflösung.

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

und Antwort würde

I am from A class 
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>] 

die Regel ist Dept erste was in diesem Fall würde bedeuten, D, B, A, C

Python verwendet normalerweise eine depth-first Reihenfolge Bei der Suche nach vererbenden Klassen Wenn jedoch zwei Klassen von derselben Klasse erben, entfernt Python die erste Erwähnung dieser Klasse aus mro.

+1

So wie Sie sehen können, ist die Reihenfolge D, B, A, C – Stryker

+1

Was meinen Sie mit "Python entfernt die erste Erwähnung dieser Klasse von Mro."? –

+1

@RuthvikVaila: Ich denke, dieser Teil ist nur schlecht angegeben. In diesem [blog post] (http://python-history.blogspot.com/2010/06/method-resolution-order.html) über die Geschichte von Python, Guido van Rossum Bemerkungen (über das MRO-Schema in Python 2.2 eingeführt) "Wenn eine Klasse bei dieser Suche dupliziert wurde, würden alle bis auf das ** letzte ** Vorkommen aus der MRO-Liste gelöscht" (Hervorhebung von mir). Dies bedeutet, dass es mehr als nur die erste "Erwähnung" der Klasse entfernen könnte. – martineau