web-dev-qa-db-fra.com

Que fait "mro ()"?

Dans Django.utils.functional.py:

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 veut dire "mro"?

106
zjm1126

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 un héritage unique, __mro__ est simplement le tuple de: la classe, sa base, sa base, etc. jusqu'à la variable object (ne fonctionne bien sûr que pour les classes de style nouveau).

Maintenant, avec multiple héritage ...:

>>> 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 n'est dupliquée et qu'aucune classe ne succède à ses ancêtres, sauf que les classes qui entrent d'abord au même niveau d'héritage multiple (comme B et C dans cet exemple) sont déjà présentes. le __mro__ de gauche à droite.

Chaque attribut que vous obtenez sur l'instance d'une classe, et pas seulement les méthodes, est conceptuellement recherché le long du __mro__. Ainsi, si plusieurs classes parmi les ancêtres définissent ce nom, cela vous indique où l'attribut sera trouvé - dans la première classe. dans le __mro__ qui définit ce nom.

184
Alex Martelli

mro() est synonyme de résolution de méthode. Il retourne une liste des types dont la classe est dérivée, dans l'ordre dans lequel ils sont recherchés.

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 d'objets.

77
Ned Batchelder

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 la profondeur d'abord, ce qui dans ce cas signifierait D, B, A, C.

Python utilise normalement un ordre depth-first 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.

8
Stryker

L'ordre de résolution sera différent dans l'héritage de diamant.

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'>)
1
Girish Gupta