¿Qué hace "mro ()"?

Respuestas:

211

Seguir a lo largo...:

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

Mientras tengamos una sola herencia, __mro__es solo la tupla de: la clase, su base, la base de su base, y así sucesivamente hastaobject (solo funciona para clases de estilo nuevo, por supuesto).

Ahora, con herencia múltiple ...:

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

... también tiene la seguridad de que, en __mro__, ninguna clase está duplicada, y ninguna clase viene después de sus antepasados, salvo que las clases que primero ingresan al mismo nivel de herencia múltiple (como B y C en este ejemplo) están en el __mro__de izquierda a derecha.

Cada atributo que obtiene en la instancia de una clase, no solo los métodos, se busca conceptualmente a lo largo del __mro__, por lo que, si más de una clase entre los antepasados ​​define ese nombre, esto le indica dónde se encontrará el atributo, en la primera clase en el __mro__que define ese nombre.

Alex Martelli
fuente
9
hola alex, ¿hay alguna diferencia entre D .__ mro__ y D.mro ().
zjm1126
26
mropuede ser personalizado por una metaclase, se llama una vez en la inicialización de la clase y el resultado se almacena en __mro__- ver docs.python.org/library/… .
Alex Martelli
23
¿Por qué se llama orden de resolución de método en lugar de orden de resolución de atributo ?
Bentley4
1
Al igual que @Alex Martelli dijo y el contenido de python-history.blogspot.com/2010/06/… , el atributo mro debe agregarse cuando se usa la nueva clase, como solo cuando Python 2.2 MRO y Python 2.3 MRO (C3) son usados.
Andy
82

mro()significa Método de resolución de la orden. Devuelve una lista de tipos de los que se deriva la clase, en el orden en que se buscan los métodos.

mro () o __mro__ solo funciona en nuevas clases de estilo. En python 3, funcionan sin ningún problema. Pero en Python 2 esas clases necesitan heredar object.

Ned Batchelder
fuente
10

Esto quizás muestre el orden de resolución.

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

y la respuesta sería

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

La regla es primero en profundidad, lo que en este caso significaría D, B, A, C.

Python normalmente usa un primer orden de profundidad cuando busca clases heredadas, pero cuando dos clases heredan de la misma clase, Python elimina la primera mención de esa clase de mro.

Stryker
fuente
1
Como puede ver, el orden es D, B, A, C
Stryker
1
¿Qué quiere decir con "Python elimina la primera mención de esa clase de mro"?
Ruthvik Vaila
2
@RuthvikVaila: Creo que esa parte está mal declarada. En esta publicación de blog sobre la historia de Python, Guido van Rossum comenta (sobre el esquema MRO introducido en Python 2.2) "Si se duplicara alguna clase en esta búsqueda, todos menos la última aparición se eliminarían de la lista MRO" (énfasis mío ) Esto implica que podría eliminar más que solo la primera "mención" de la clase.
martineau
1

El orden de resolución será diferente en la herencia de diamantes.

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'>)
Gupta Girish
fuente
pero ¿por qué la resolución es diferente?
Vadim
En el escenario de herencia múltiple, cualquier atributo especificado se busca primero en la clase actual. Si no se encuentra, la búsqueda continúa en clases primarias de manera profunda primero, izquierda-derecha sin buscar la misma clase dos veces.
Girish Gupta
lo siento, pero no entiendo por qué en el primer caso se va, class B3pero en el segundo caso se va class Adespuésclass B1
Vadim