Перебирать подклассы данного класса в данном модуле

В Python, учитывая модуль X и класс Y, как я могу выполнить итерацию или сгенерировать список всех подклассов Y, существующих в модуле X?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
17
0
9 316
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вот один из способов сделать это:

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

Мое решение не будет возвращать классы, которые не являются прямыми потомками cls. Решение quamrana, приведенное ниже, найдет любой класс, у которого есть cls где-то в его родословной.

Chris AtLee 15.09.2008 19:41

Учитывая модуль 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'>)]

Могу ли я предположить, что ни один из ответов Криса Атли и zacherates не соответствует требованиям? Я думаю, что эта модификация для зацератного ответа лучше:

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

Причина, по которой я не согласен с данными ответами, заключается в том, что первый не создает классов, которые являются удаленным подклассом данного класса, а второй включает данный класс.

Хотя предложение Quamrana работает нормально, есть несколько возможных улучшений, которые я хотел бы предложить, чтобы сделать его более питоническим. Они полагаются на использование модуля проверки из стандартной библиотеки.

  1. Вы можете избежать вызова getattr, используя inspect.getmembers()
  2. Попытки / уловки можно избежать, используя inspect.isclass()

С их помощью вы можете свести все это к пониманию единого списка, если хотите:

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

Отлично работает, но мой ответ также возвращает базовый класс (тот, который я отправляю с помощью clazz), есть идеи?

fredrik 12.02.2010 17:55

Фредрик, оказывается, что issubclass (Foo, Foo) истинно. Хотя это легко исправить. добавить "а не cls is clazz" к пониманию списка

runeh 20.03.2010 02:32

-1: код не работает. правильно было бы: cls for name, cls in inspect.getmembers(module)

tback 17.12.2010 17:58

Другие вопросы по теме