Что делает «mro ()»?

Ответы:

211

Следуйте ...:

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

Пока у нас есть единичное наследование, __mro__это просто кортеж из: класса, его базы, его базы и т. Д. object(Работает, конечно, только для классов нового стиля).

Теперь с множественным наследованием ...:

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

... вы также получаете уверенность в том, что __mro__ни один класс не дублируется и ни один класс не идет после своих предков, за исключением тех классов, которые сначала входят на одном уровне множественного наследования (например, B и C в этом примере), находятся в __mro__слева направо.

Каждый атрибут, который вы получаете в экземпляре класса, а не только методы, концептуально просматривается вдоль __mro__, поэтому, если более одного класса среди предков определяют это имя, это сообщает вам, где будет найден атрибут - в первом классе в то, __mro__что определяет это имя.

Алекс Мартелли
источник
9
привет, Алекс, есть ли разница между D .__ mro__ и D.mro ().
zjm1126 06
26
mroможет быть настроен с помощью метакласса, вызывается один раз при инициализации класса, а результат сохраняется в __mro__- см. docs.python.org/library/… .
Alex Martelli
23
Почему это называется порядком разрешения методов, а не порядком разрешения атрибутов ?
Bentley4
1
Так же, как сказал @Alex Martelli и содержимое python-history.blogspot.com/2010/06/… , атрибут mro должен быть добавлен при использовании нового класса, как только когда Python 2.2 MRO и Python 2.3 MRO (C3) используются.
Энди
82

mro()означает Порядок разрешения методов. Он возвращает список типов, производных от класса, в порядке их поиска для методов.

mro () или __mro__ работает только с новыми классами стилей. В python 3 они работают без проблем. Но в Python 2 эти классы должны наследовать от object.

Нед Батчелдер
источник
10

Возможно, это покажет порядок разрешения.

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

и ответ будет

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

Правило - сначала глубина, что в данном случае будет означать D, B, A, C.

Python обычно использует порядок глубины при поиске наследующих классов, но когда два класса наследуются от одного и того же класса, Python удаляет первое упоминание этого класса из mro.

Stryker
источник
1
Итак, как вы можете видеть, порядок следующий: D, B, A, C
Stryker
1
Что вы имеете в виду под «Python удаляет первое упоминание этого класса из mro.»?
Ruthvik Vaila
2
@RuthvikVaila: Я думаю, что эта часть плохо сформулирована. В этом сообщении блога об истории Python Гвидо ван Россум отмечает (о схеме MRO, представленной в Python 2.2): «Если какой-либо класс дублировался в этом поиске, все, кроме последнего вхождения, были бы удалены из списка MRO» (выделено мной ). Это означает, что он может удалить не только первое «упоминание» о классе.
Мартино
1

Порядок разрешения будет другим в наследовании алмазов.

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а во втором случае идет class Aпослеclass B1
Вадим