2010-01-06 7 views
91

En django.utils.functional.py:Que fait "mro()"?

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

Je ne comprends pas mro(). Que fait-il et que signifie "mro"?

+2

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

+1

Ooph, quelle lecture longue c'est. – paulmelnikow

Répondre

164

suivre ...:

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

Tant que nous avons l'héritage unique, __mro__ est juste le tuple: la classe, sa base, la base de sa base, et ainsi de suite jusqu'à object (seulement travaille pour des cours de style nouveau bien sûr).

Maintenant, avec l'héritage multiple ...:

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

... vous obtenez également l'assurance que, dans __mro__, aucune classe est dupliqué, et aucune classe vient après ses ancêtres, sauf que Les classes qui entrent pour la première fois au même niveau d'héritage multiple (comme B et C dans cet exemple) se trouvent dans le __mro__ de gauche à droite. Chaque attribut que vous obtenez sur l'instance d'une classe, pas seulement sur les méthodes, est conceptuellement recherché le long du __mro__, donc, si plus d'une classe parmi les ancêtres définit ce nom, cela vous indique où l'attribut sera trouvé - dans la première classe du __mro__ qui définit ce nom.

+7

salut, alex, existe-t-il une différence entre D .__ mro__ et D.mro(). – zjm1126

+19

'mro' peut être personnalisé par une métaclasse, est appelé une fois lors de l'initialisation de classe, et le résultat est stocké dans' __mro__' - voir http://docs.python.org/library/stdtypes.html?highlight=mro# classe .__ mro__. –

+13

Pourquoi est-il appelé ** ordre de résolution de méthode ** au lieu de ** ordre de résolution d'attribut **? – Bentley4

69

mro() représente l'ordre de résolution des méthodes. Il renvoie une liste de types dont la classe est dérivée, dans l'ordre où ils sont recherchés pour les méthodes.

MRO() ou __mro__ ne fonctionne que sur les nouvelles classes de style. En python 3, ils fonctionnent sans aucun problème. Mais en python 2, ces classes doivent hériter des objets.

7

Cela montrerait peut-être l'ordre de résolution.

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

et la réponse serait

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

La règle est Dept première qui, dans ce cas, cela signifierait D, B, A, C

Python utilise normalement une profondeur d'abord ordre lors de la recherche de classes héritées Mais lorsque deux classes héritent de la même classe, Python supprime la première mention de cette classe de mro.

+1

Ainsi que vous pouvez voir la commande est D, B, A, C – Stryker

+1

Que voulez-vous dire par "Python supprime la première mention de cette classe de mro."? –

+1

@RuthvikVaila: Je pense que cette partie est juste mal indiquée. Dans ce [post du blog] (http://python-history.blogspot.com/2010/06/method-resolution-order.html) sur l'histoire de Python, Guido van Rossum remarque (à propos du schéma MRO introduit en Python 2.2) "Si une classe était dupliquée dans cette recherche, toutes les occurrences sauf la dernière ** seraient supprimées de la liste MRO" (soulignement le mien). Cela implique qu'il pourrait supprimer plus que la première "mention" de la classe. – martineau