Was macht "mro ()"?


Antworten:


211

Folgen...:

>>> 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 eine einzelne Vererbung haben, __mro__ist dies nur das Tupel von: der Klasse, ihrer Basis, der Basis ihrer Basis usw. bis object(funktioniert natürlich nur für Klassen neuen Stils).

Jetzt mit Mehrfachvererbung ...:

>>> 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__keine Klasse dupliziert wird und keine Klasse nach ihren Vorfahren kommt, außer dass Klassen, die zuerst auf derselben Ebene der Mehrfachvererbung eingegeben werden (wie B und C in diesem Beispiel), in der __mro__links nach rechts.

Jedes Attribut, das Sie auf der Instanz einer Klasse erhalten, nicht nur Methoden, wird konzeptionell entlang der nachgeschlagen. __mro__Wenn also mehr als eine Klasse unter den Vorfahren diesen Namen definiert, erfahren Sie, wo sich das Attribut befindet - in der ersten Klasse in das __mro__, das diesen Namen definiert.


9
Hallo Alex, gibt es einen Unterschied zwischen D .__ mro__ und D.mro ()?
zjm1126

26
mrokann durch eine Metaklasse angepasst werden, wird bei der Klasseninitialisierung einmal aufgerufen und das Ergebnis wird in gespeichert __mro__- siehe docs.python.org/library/… .
Alex Martelli

23
Warum heißt es Methodenauflösungsreihenfolge anstelle von Attributauflösungsreihenfolge ?
Bentley4

1
Genau wie @Alex Martelli sagte und der Inhalt von python-history.blogspot.com/2010/06/… sollte das mro- Attribut hinzugefügt werden, wenn die neue Klasse verwendet wird, wie nur, wenn Python 2.2 MRO und Python 2.3 MRO (C3) werden verwendet.
Andy

82

mro()steht für Method Resolution Order. Es gibt eine Liste der Typen zurück, von denen die Klasse abgeleitet ist, in der Reihenfolge, in der nach Methoden gesucht wird.

mro () oder __mro__ funktioniert nur bei neuen Stilklassen . In Python 3 funktionieren sie ohne Probleme. In Python 2 müssen diese Klassen jedoch erben object.


10

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

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äre

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

Die Regel lautet "Tiefe zuerst", was in diesem Fall D, B, A, C bedeuten würde.

Python verwendet normalerweise eine Tiefen-First- Reihenfolge bei der Suche nach ererbenden Klassen. Wenn jedoch zwei Klassen von derselben Klasse erben, entfernt Python die erste Erwähnung dieser Klasse aus mro.


1
Wie Sie sehen können, ist die Reihenfolge D, B, A, C
Stryker

1
Was meinst du mit "Python entfernt die erste Erwähnung dieser Klasse von mro."?
Ruthvik Vaila

2
@ RuthvikVaila: Ich denke, dieser Teil ist nur schlecht angegeben. In diesem Blog-Beitrag über die Geschichte von Python bemerkt Guido van Rossum (über das in Python 2.2 eingeführte MRO-Schema): "Wenn eine Klasse bei dieser Suche dupliziert würde, würden alle bis auf das letzte Vorkommen aus der MRO-Liste gelöscht" (Hervorhebung von mir) ). Dies impliziert, dass mehr als nur die erste "Erwähnung" der Klasse entfernt werden könnte.
Martineau

1

Die Reihenfolge der Auflösung unterscheidet sich in der Diamantvererbung.

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

aber warum ist die Auflösung anders?
Vadim

Im Mehrfachvererbungsszenario wird jedes angegebene Attribut zuerst in der aktuellen Klasse durchsucht. Wenn nicht gefunden, wird die Suche in übergeordneten Klassen in der Tiefe zuerst links und rechts fortgesetzt, ohne dass dieselbe Klasse zweimal durchsucht wird.
Girish Gupta

Entschuldigung, aber ich verstehe nicht, warum es im ersten Fall geht, class B3aber im zweiten Fall geht es class Anachclass B1
Vadim
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.