2010-11-04 3 views
5

J'aimerais pouvoir parcourir toutes les classes de base, directes et indirectes, d'une classe donnée, y compris la classe elle-même. Ceci est utile dans le cas où vous avez une métaclasse qui examine une classe Options interne de toutes ses bases.Existe-t-il une fonction standard pour itérer sur les classes de base?

Pour ce faire, j'écrit ce qui suit:

def bases(cls): 
    yield cls 
    for direct_base in cls.__bases__: 
     for base in bases(direct_base): 
      yield base 

Y at-il une fonction standard de le faire pour moi?

Répondre

12

Il existe une méthode qui peut les renvoyer tous, dans l'ordre de résolution de méthode (MRO): inspect.getmro. Voir ici:

http://docs.python.org/library/inspect.html#inspect.getmro

Il leur revient en tant que tuple, que vous pouvez ensuite parcourir en une seule boucle vous:

import inspect 
for base_class in inspect.getmro(foo): 
    # do something 

Ceci a l'avantage de côté ne cédant chaque classe de base une fois , même si vous avez un héritage en forme de losange.

0

Je ne sais pas exactement si elle est ce que vous cherchez, mais un coup d'oeil à someclass.__mro__, MRO être Méthode ordre de résolution

http://docs.python.org/library/stdtypes.html?highlight=mro#class.__mro__

+1

Ceci a l'inconvénient (discutable) de ne pas fonctionner avec des classes de style ancien. 'inspect.getmro' renvoie' cls .__ mro__' s'il est présent (sur les nouvelles classes de style) et effectue une recherche personnalisée si ce n'est pas le cas. (Fait amusant: Vous pouvez générer une erreur de récurrence en créant une ancienne hiérarchie de classe de style avec plus de classes que la profondeur de récursivité maximale et en appelant 'getmro') – aaronasterling

1

Ambre a la bonne réponse pour la monde réel, mais je vais montrer une façon correcte de le faire. Votre solution inclura deux classes deux fois si deux classes de base héritent elles-mêmes de la même classe de base.

def bases(cls): 
    classes = [cls] 
    i = 0 
    while 1: 
     try: 
      cls = classes[i] 
     except IndexError: 
      return classes 
     i += 1 
     classes[i:i] = [base for base in cls.__bases__ if base not in classes] 

La seule partie un peu délicate est l'endroit où nous utilisons la tranche. C'est nécessaire pour effectuer ce genre de recherche en profondeur sans utiliser de récursion. Tout ce qu'il fait est de prendre les classes de base de la classe en cours d'examen et de les insérer immédiatement après, afin que la première classe de base soit la prochaine classe examinée. Une solution très lisible (qui a sa propre laideur) est disponible dans l'implémentation de inspect.getmro dans la bibliothèque standard.

+0

Merci. Je me suis rendu compte après que j'ai posté que la mienne pourrait frapper la même classe deux fois mais dans mon cas cela n'a pas importé. –

Questions connexes