ProgrammationDéveloppeur Backend

Comment fonctionne le mécanisme d'ordre de résolution des méthodes (MRO - Method Resolution Order) en Python lors de l'héritage des classes ? Pourquoi est-il important de comprendre l'ordre de résolution des méthodes, et comment peut-on le connaître / le modifier ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

L'ordre de résolution des méthodes (MRO) est un mécanisme en Python qui détermine dans quel ordre les classes seront examinées lors de la recherche de méthodes et d'attributs en cas d'héritage multiple.

La linéarisation C3 est un algorithme utilisé pour construire la séquence de résolution des méthodes. Comprendre le MRO est crucial lors de la conception d'une hiérarchie de classes complexe, afin d'éviter les ambiguïtés et les comportements inattendus des méthodes.

Pour connaître le MRO d'une classe, on peut utiliser l'attribut __mro__ ou la fonction mro():

class A: def hello(self): print('A') class B(A): def hello(self): print('B') class C(A): def hello(self): print('C') class D(B, C): pass print(D.__mro__) # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) obj = D() obj.hello() # 'B', parce que B vient avant C dans le MRO

Il n'est pas possible de modifier explicitement le MRO, mais on peut contrôler l'ordre des classes de base.

Question piège

Dans quel ordre les méthodes seront-elles appelées si une classe hérite de plusieurs parents ? Par exemple :

class Base: def foo(self): print('Base') class Left(Base): def foo(self): print('Left') super().foo() class Right(Base): def foo(self): print('Right') super().foo() class Child(Left, Right): pass Child().foo()

Beaucoup s'attendent à ce que "foo" soit appelé d'abord depuis Left, puis de Right, puis Base — et c'est le cas. Cependant, si on change l'ordre des classes de base (class Child(Right, Left)), l'ordre changera !

Réponse correcte :

L'ordre des appels sera celui défini dans le MRO. Dans le premier cas — Left, Right, Base. Le MRO est construit selon un algorithme défini (linéarisation C3) :

[Child, Left, Right, Base, object]

Exemples d'erreurs réelles dues à une méconnaissance des subtilités du sujet


Histoire

Héritage multiple de logique, écrasement de méthode

L'équipe de développement a utilisé l'héritage multiple pour des mixins. Il s'est avéré qu'en raison d'un ordre incorrect des classes de base, la logique commune du mixin a été "écrasée" par la classe fille, et une partie de la logique métier n'était pas exécutée, entraînant une perte de données.


Histoire

Le mauvais méthode du parent est appelée

Dans la méthode de finalisation (__del__), il était prévu que la méthode de la classe de base soit appelée. Cependant, en raison d'une mauvaise compréhension du MRO, une autre méthode, héritée du mixin, a été appelée, où le nettoyage des ressources n'était pas effectué. En conséquence — fuite de mémoire.


Histoire

Utilisation de super() sans comprendre la chaîne d'appels

Dans un projet Python 3, le client a réécrit une partie du code avec héritage multiple, oubliant de mettre à jour les appels via super(). Cela a conduit à des situations de récursion infinie, où la méthode s'appelait toujours elle-même en raison d'un ordre de résolution des méthodes erroné.