Iterar sobre subclasses de uma determinada classe em um determinado módulo
Pergunta
Em Python, dado um módulo X e uma classe Y, como posso iterar ou gerar uma lista de todas as subclasses de Y que existem no módulo X?
Solução
Esta é uma maneira de fazer isso:
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
Outras dicas
Embora a sugestão de Quamrana funcione bem, há algumas melhorias possíveis que gostaria de sugerir para torná-la mais pitônica.Eles dependem do uso do módulo inspecionar da biblioteca padrão.
- Você pode evitar a chamada getattr usando
inspect.getmembers()
- O try/catch pode ser evitado usando
inspect.isclass()
Com eles, você pode reduzir tudo a uma única compreensão de lista, se desejar:
def find_subclasses(module, clazz):
return [
cls
for name, cls in inspect.getmembers(module)
if inspect.isclass(cls) and issubclass(cls, clazz)
]
Posso sugerir que nenhuma das respostas de Chris AtLee e zacherates atende aos requisitos?Acho que esta modificação na resposta do zacerates é melhor:
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
A razão pela qual discordo das respostas dadas é que a primeira não produz classes que sejam uma subclasse distante da classe dada, e a segunda inclui a classe dada.
Dado o módulo 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'>)]