2010-01-06 41 views
91

En django.utils.functional.py:¿Qué hace "mro()"?

for t in type(res).mro(): # <----- this 
    if t in self.__dispatch: 
     return self.__dispatch[t][funcname](res, *args, **kw) 

No entiendo mro(). ¿Qué hace y qué significa "mro"?

+2

http://www.python.org/download/releases/2.3/mro – GodMan

+1

Ooph, que larga lectura es esa. – paulmelnikow

Respuesta

164

lo sigue ...:

>>> 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 tenemos la herencia simple, __mro__ es sólo la tupla de: la clase, su base, la base de su base, y así sucesivamente hasta object (sólo trabaja para clases de nuevo estilo, por supuesto).

Ahora, con múltiples herencia ...:

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

... También tendrá la seguridad de que, en __mro__, ninguna clase se duplica, y ninguna clase viene después de sus antepasados, salvo que las clases que ingresan primero en el 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 obtienes en la instancia de una clase, no solo en los métodos, se busca conceptualmente a lo largo del __mro__, entonces, si más de una clase entre los antepasados ​​define ese nombre, esto te indica dónde se encontrará el atributo. en la primera clase en el __mro__ que define ese nombre.

+7

hola, alex, ¿hay alguna diferencia entre D .__ mro__ y D.mro(). – zjm1126

+19

'mro' se puede personalizar mediante una metaclase, se llama una vez en la inicialización de la clase, y el resultado se almacena en' __mro__' - ver http://docs.python.org/library/stdtypes.html?highlight=mro# clase .__ mro__. –

+13

¿Por qué se llama ** orden de resolución de método ** en lugar de ** orden de resolución de atributo **? – Bentley4

69

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

MRO() o __mro__ sólo funciona en nuevas clases de estilo. En python 3, funcionan sin problemas. Pero en python 2 esas clases necesitan heredar de los objetos.

7

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 dept primero que en este caso significaría D, B, A, C

Python normalmente utiliza un profundidad-primero orden al buscar clases heredadas Pero cuando dos clases heredan de la misma clase, Python elimina la primera mención de esa clase de mro.

+1

Entonces, 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"? –

+1

@RuthvikVaila: Creo que esa parte está mal definida. En esta [publicación de blog] (http://python-history.blogspot.com/2010/06/method-resolution-order.html) sobre la historia de Python, comenta Guido van Rossum (sobre el esquema de MRO introducido en Python 2.2) "Si se duplicó alguna clase en esta búsqueda, todas las apariciones menos la ** última ** se eliminarán de la lista de MRO" (énfasis mío). Esto implica que podría eliminar algo más que la primera "mención" de la clase. – martineau