2008-09-04 7 views

Respuesta

11

Ésta es una forma de hacerlo:

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 
+0

Mi solución no devolverá las clases que no sean descendientes directas de 'cls'. La solución de quamrana a continuación encontrará cualquier clase que tenga 'cls' en algún lugar de su ascendencia. –

1

Dado el módulo de 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'>)] 
4

¿Puedo sugerir que ninguna de las respuestas de Chris AtLee y zacherates cumplir con los requisitos? creo que esta modificación a zacerates respuesta es mejor:

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 razón estoy de acuerdo con las respuestas dadas es que el primero no produce las clases que son una subclase distante de la clase dada, y el segundo incluye el dado clase.

20

Aunque la sugerencia de Quamrana funciona bien, hay un par de posibles mejoras que me gustaría sugerir para hacerlo más pitónico. Confían en usar el módulo de inspección de la biblioteca estándar.

  1. Usted puede evitar la llamada getattr utilizando inspect.getmembers()
  2. El try/catch se pueden evitar mediante el uso de inspect.isclass()

Con ellos, se puede reducir todo a una lista única de comprensión si como:

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

Funciona muy bien, pero mi respuesta también devuelve la clase base (la que envío con clazz), ¿alguna idea? – fredrik

+0

Fredrik, resulta que issubclass (Foo, Foo) es Verdadero. Sin embargo, una solución fácil. agregar "y no cls es clazz" a la lista de comprensión – runeh

+2

-1: el código no funciona. corregir sería: 'cls para nombre, cls en inspeccionar.obtener miembros (módulo)' – tback

Cuestiones relacionadas