2008-09-04 10 views

Antwort

11

Hier ist eine Möglichkeit, es zu tun:

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

Meine Lösung wird keine Klassen zurückgeben, die keine direkten Nachkommen von 'cls' sind. Die Lösung von Quamrana unten findet jede Klasse, die irgendwo in ihrer Herkunft "cls" hat. –

1

Da das Modul 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

Kann ich vorschlagen, dass keine der Antworten von Chris AtLee und zacherates die Anforderungen erfüllen? Ich denke, diese Änderung zu zacerates Antwort ist besser:

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 

Der Grund, warum ich mit den Antworten andere Meinung ist, dass die erste nicht-Klassen produziert, die eine entfernte Unterklasse der gegebenen Klasse sind, und der zweite enthält die gegebenen Klasse.

20

Obwohl Quamranas Vorschlag gut funktioniert, gibt es ein paar mögliche Verbesserungen, die ich vorschlagen möchte, um es pythonischer zu machen. Sie verwenden das inspect-Modul aus der Standardbibliothek. wenn Sie

  1. Sie können die getattr Anruf vermeiden, indem inspect.getmembers()
  2. Der try/catch verwenden, können mithilfe von inspect.isclass()

mit denen vermieden werden kann, können Sie das Ganze auf eine einzige Liste Verständnis reduzieren wie:

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

Funktioniert gut, aber meine Antwort gibt auch die Basisklasse zurück (die ich mit cazz einschicke), irgendeine Idee? – fredrik

+0

Fredrik, stellt sich heraus, issubclass (Foo, Foo) ist True. Einfache Lösung, obwohl. add "und nicht cls ist clazz" zum Listenverständnis – runeh

+2

-1: Code funktioniert nicht. richtig wäre es: 'cls für name, cls in inspect.getmembers (modul)' – tback

Verwandte Themen