Itérer sur les sous-classes d'une classe donnée dans un module donné
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 ?
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.
- Vous pouvez éviter l'appel getattr en utilisant
inspect.getmembers()
- 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'>)]