Iterieren Sie über Unterklassen einer bestimmten Klasse in einem bestimmten Modul
Frage
Wie kann ich in Python bei einem gegebenen Modul X und einer Klasse Y iterieren oder eine Liste aller Unterklassen von Y generieren, die in Modul X vorhanden sind?
Lösung
Hier ist eine Möglichkeit:
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
Andere Tipps
Obwohl Quamranas Vorschlag gut funktioniert, möchte ich einige mögliche Verbesserungen vorschlagen, um ihn pythonischer zu gestalten.Sie verlassen sich auf die Verwendung des Inspektionsmoduls aus der Standardbibliothek.
- Sie können den getattr-Aufruf vermeiden, indem Sie verwenden
inspect.getmembers()
- Der Try/Catch kann durch die Verwendung vermieden werden
inspect.isclass()
Mit diesen können Sie das Ganze auf Wunsch auf ein einziges Listenverständnis reduzieren:
def find_subclasses(module, clazz):
return [
cls
for name, cls in inspect.getmembers(module)
if inspect.isclass(cls) and issubclass(cls, clazz)
]
Kann ich vorschlagen, dass keine der Antworten von Chris AtLee und Zacherates die Anforderungen erfüllt?Ich denke, diese Änderung der 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 gegebenen Antworten nicht einverstanden bin, liegt darin, dass die erste keine Klassen erzeugt, die eine entfernte Unterklasse der gegebenen Klasse sind, und die zweite die gegebene Klasse einschließt.
Gegeben sei 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'>)]