Itérer sur les sous-classes d'une classe donnée dans un module donné

StackOverflow https://stackoverflow.com/questions/44352

  •  09-06-2019
  •  | 
  •  

Question

En Python, étant donné un module X et une classe Y, comment puis-je itérer ou générer une liste de toutes les sous-classes de Y qui existent dans le module X ?

Était-ce utile?

La solution

Voici une façon de procéder :

import inspect

def get_subclasses(mod, cls):
    """Yield the classes in module ``mod`` that inherit from ``cls``"""
    for name, obj in inspect.getmembers(mod):
        if hasattr(obj, "__bases__") and cls in obj.__bases__:
            yield obj

Autres conseils

Bien que la suggestion de Quamrana fonctionne bien, j'aimerais suggérer quelques améliorations possibles pour la rendre plus pythonique.Ils s'appuient sur l'utilisation du module inspect de la bibliothèque standard.

  1. Vous pouvez éviter l'appel getattr en utilisant inspect.getmembers()
  2. Le try/catch peut être évité en utilisant inspect.isclass()

Avec ceux-ci, vous pouvez réduire le tout à une seule compréhension de liste si vous le souhaitez :

def find_subclasses(module, clazz):
    return [
        cls
            for name, cls in inspect.getmembers(module)
                if inspect.isclass(cls) and issubclass(cls, clazz)
    ]

Puis-je suggérer qu'aucune des réponses de Chris AtLee et de Zacherates ne remplit les conditions ?Je pense que cette modification de la réponse aux zacerates est meilleure :

def find_subclasses(module, clazz):
    for name in dir(module):
        o = getattr(module, name)
        try:
            if (o != clazz) and issubclass(o, clazz):
                yield name, o
        except TypeError: pass

La raison pour laquelle je ne suis pas d'accord avec les réponses données est que la première ne produit pas de classes qui sont une sous-classe distante de la classe donnée et que la seconde inclut la classe donnée.

Étant donné le module foo.py

class foo(object): pass
class bar(foo): pass
class baz(foo): pass

class grar(Exception): pass

def find_subclasses(module, clazz):
    for name in dir(module):
        o = getattr(module, name)

        try: 
             if issubclass(o, clazz):
             yield name, o
        except TypeError: pass

>>> import foo
>>> list(foo.find_subclasses(foo, foo.foo))
[('bar', <class 'foo.bar'>), ('baz', <class 'foo.baz'>), ('foo', <class 'foo.foo'>)]
>>> list(foo.find_subclasses(foo, object))
[('bar', <class 'foo.bar'>), ('baz', <class 'foo.baz'>), ('foo', <class 'foo.foo'>), ('grar', <class 'foo.grar'>)]
>>> list(foo.find_subclasses(foo, Exception))
[('grar', <class 'foo.grar'>)]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top