Co robi „mro ()”?


Odpowiedzi:


211

Idź dalej ...:

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

Dopóki mamy pojedyncze dziedziczenie, __mro__jest to po prostu krotka: klasa, jej baza, jej baza itd., Aż do object(oczywiście działa tylko dla klas w nowym stylu).

Teraz z dziedziczeniem wielokrotnym ...:

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

... zyskujesz również pewność, że w programie __mro__żadna klasa nie jest zduplikowana i żadna klasa nie występuje po swoich przodkach, poza tym, że klasy, które jako pierwsze wchodzą na ten sam poziom dziedziczenia wielokrotnego (jak B i C w tym przykładzie) znajdują się w __mro__z lewej na prawą.

Każdy atrybut, który otrzymujesz w instancji klasy, a nie tylko metody, jest koncepcyjnie przeglądany wzdłuż __mro__, więc jeśli więcej niż jedna klasa wśród przodków definiuje tę nazwę, to mówi ci, gdzie zostanie znaleziony atrybut - w pierwszej klasie w __mro__który definiuje tę nazwę.


9
cześć alex, czy jest jakaś różnica między D .__ mro__ i D.mro ().
zjm1126

26
mromożna dostosować za pomocą metaklasy, jest wywoływana raz podczas inicjalizacji klasy, a wynik jest przechowywany w __mro__- patrz docs.python.org/library/… .
Alex Martelli,

23
Dlaczego nazywa się to kolejnością rozwiązywania metod zamiast kolejności rozwiązywania atrybutów ?
Bentley4

1
Tak jak powiedział @Alex Martelli i zawartość python-history.blogspot.com/2010/06/… , atrybut mro należy dodać, gdy używana jest nowa klasa, tak jak tylko wtedy, gdy Python 2.2 MRO i Python 2.3 MRO (C3) są używane.
andy

82

mro()oznacza Method Resolution Order. Zwraca listę typów, z których pochodzi klasa, w kolejności wyszukiwania metod.

mro () lub __mro__ działa tylko na nowych klasach stylów. W Pythonie 3 działają bez żadnych problemów. Ale w Pythonie 2 te klasy muszą dziedziczyć z object.


10

To być może pokazałoby kolejność rozdzielczości.

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

a odpowiedź byłaby

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

Reguła jest głębi, co w tym przypadku oznaczałoby D, B, A, C.

Python zwykle używa kolejności od początku do głębi podczas wyszukiwania klas dziedziczących, ale gdy dwie klasy dziedziczą z tej samej klasy, Python usuwa pierwszą wzmiankę o tej klasie z mro.


1
Jak widać, zamówienie to D, B, A, C
Stryker

1
Co masz na myśli, mówiąc „Python usuwa pierwszą wzmiankę o tej klasie z mro”?
Ruthvik Vaila,

2
@RuthvikVaila: Myślę, że ta część jest po prostu słabo opisana. W tym wpisie na blogu dotyczącym historii Pythona, Guido van Rossum zauważa (o schemacie MRO wprowadzonym w Pythonie 2.2) "Gdyby jakaś klasa została zduplikowana w tym wyszukiwaniu, wszystkie z wyjątkiem ostatniego wystąpienia zostałyby usunięte z listy MRO" (moje podkreślenie ). Oznacza to, że może usunąć więcej niż tylko pierwszą „wzmiankę” o klasie.
martineau

1

Kolejność rozdzielczości będzie inna w przypadku dziedziczenia diamentów.

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

ale dlaczego rozdzielczość jest inna?
Vadim,

W scenariuszu wielokrotnego dziedziczenia każdy określony atrybut jest najpierw przeszukiwany w bieżącej klasie. Jeśli nie zostanie znaleziony, przeszukiwanie jest kontynuowane w klasach nadrzędnych w pierwszej kolejności, od lewej do prawej, bez dwukrotnego przeszukiwania tej samej klasy.
Girish Gupta

przepraszam, ale nie rozumiem, dlaczego w pierwszym przypadku to się dzieje, class B3ale w drugim przypadku idzie class Apoclass B1
Vadim
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.