O que "mro ()" faz?


Respostas:


211

Acompanhe ...:

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

Desde que tenhamos uma herança única, __mro__é apenas a tupla de: a classe, sua base, sua base e assim por diante.object (funciona apenas para classes de novo estilo, é claro).

Agora, com herança múltipla ...:

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

... você também tem a garantia de que, em __mro__, nenhuma classe é duplicada e nenhuma classe vem após seus ancestrais, exceto que as classes que primeiro entram no mesmo nível de herança múltipla (como B e C neste exemplo) estão no __mro__esquerda para a direita.

Todos os atributos que você obtém na instância de uma classe, não apenas métodos, são conceitualmente pesquisados ​​ao longo de __mro__, portanto, se mais de uma classe entre os ancestrais definir esse nome, isso informa onde o atributo será encontrado - na primeira classe em o __mro__que define esse nome.


9
oi alex, existe alguma diferença entre D .__ mro__ e D.mro ().
zjm1126

26
mropode ser personalizado por uma metaclasse, é chamado uma vez na inicialização da classe e o resultado é armazenado em __mro__- consulte docs.python.org/library/… .
Alex Martelli

23
Por que é chamado de ordem de resolução do método em vez de ordem de resolução de atributo ?
Bentley4

1
Assim como @Alex Martelli disse e o conteúdo de python-history.blogspot.com/2010/06/… , o atributo mro deve ser adicionado quando a nova classe for usada, assim como somente quando Python 2.2 MRO e Python 2.3 MRO (C3) são usados.
andy

82

mro()significa Ordem de resolução de método. Ele retorna uma lista de tipos dos quais a classe é derivada, na ordem em que são pesquisados ​​por métodos.

mro () ou __mro__ funciona apenas em novas classes de estilo. No python 3, eles funcionam sem problemas. Mas no python 2 essas classes precisam herdar object.


10

Talvez isso mostre a ordem da resolução.

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 resposta seria

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

A regra é a profundidade em primeiro lugar, o que neste caso significaria D, B, A, C.

O Python normalmente usa uma ordem de profundidade ao pesquisar classes herdadas, mas quando duas classes são herdadas da mesma classe, o Python remove a primeira menção dessa classe do mro.


1
Então, como você pode ver, a ordem é D, B, A, C
Stryker:

1
O que você quer dizer com "Python remove a primeira menção dessa classe do mro".
Ruthvik Vaila

2
@RuthvikVaila: Eu acho que essa parte está mal declarada. Nesta postagem do blog sobre a história do Python, Guido van Rossum comenta (sobre o esquema de MRO introduzido no Python 2.2) "Se alguma classe foi duplicada nesta pesquisa, todos, exceto a última ocorrência, seriam excluídos da lista de MRO" (grifo meu ) Isso implica que ele poderia remover mais do que apenas a primeira "menção" da classe.
martineau

1

A ordem da resolução será diferente na herança do diamante.

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

mas por que a resolução é diferente?
Vadim

No cenário de herança múltipla, qualquer atributo especificado é pesquisado primeiro na classe atual. Se não for encontrada, a pesquisa continuará nas classes pai de maneira aprofundada, esquerda-direita, sem pesquisar duas vezes na mesma classe.
Girish Gupta

desculpe, mas eu não entendo por que, no primeiro caso, é ir, class B3mas no segundo caso, é ir paraclass A depoisclass B1
Vadim
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.