Перебор подклассов данного класса в данном модуле
Вопрос
В Python, учитывая модуль X и класс Y, как я могу выполнить итерацию или сгенерировать список всех подклассов Y, которые существуют в модуле X?
Решение
Вот один из способов сделать это:
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
Другие советы
Хотя предложение Quamrana работает нормально, есть пара возможных улучшений, которые я хотел бы предложить, чтобы сделать его более питоническим.Они полагаются на использование модуля inspect из стандартной библиотеки.
- Вы можете избежать вызова getattr, используя
inspect.getmembers()
- Попытки / перехвата можно избежать, используя
inspect.isclass()
С их помощью вы можете свести все это к пониманию одного списка, если хотите:
def find_subclasses(module, clazz):
return [
cls
for name, cls in inspect.getmembers(module)
if inspect.isclass(cls) and issubclass(cls, clazz)
]
Могу ли я предположить, что ни один из ответов Криса Этли и Закератаса не соответствует требованиям?Я думаю, что эта модификация ответа zacerates лучше:
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
Причина, по которой я не согласен с приведенными ответами, заключается в том, что первый не создает классы, которые являются удаленным подклассом данного класса, а второй включает данный класс.
Учитывая модуль 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'>)]