logo

Поиск всех подклассов определенного класса в Python

Быстрый ответ

Python
Скопировать код
Cls = globals()['MyClass']  # Замените 'MyClass' на ту часть, которая соответствует названию вашего класса
subclasses = Cls.__subclasses__()

Для поиска подклассов для 'MyClass', выполните следующие действия:

  • Получите экземпляр класса с помощью функции globals():

    Python
    Скопировать код
    Cls = globals()['MyClass']
  • Определите непосредственных наследников класса с помощью метода __subclasses__():

    Python
    Скопировать код
    subclasses = Cls.__subclasses__()

Продолжайте исследование с использованием рекурсии

Для изучения всех уровней наследования, включая прямых наследников и более дальних потомков класса, примените следующий процесс:

Python
Скопировать код
def find_all_kids(cls):
    """Находим всех потомков на всех уровнях наследования."""
    for kiddo in cls.__subclasses__():
        yield kiddo
        yield from find_all_kids(kiddo)  # Рекурсия здесь играет важную роль

# Пример использования
all_kids = list(find_all_kids(Cls))  # Собираем всю многочисленную родню

Импортируйте для нахождения большего количества наследников

Метод __subclasses__() обнаружит лишь те подклассы, которые были импортированы. Чтобы выявить больше "родственников", следуйте двум шагам:

  1. Импортируйте известные модули.
  2. Для отыскания неизвестных подклассов воспользуйтесь importlib:

    Python
    Скопировать код
    import importlib
    module = importlib.import_module('module_name')  # Здесь модуль, в котором может "проживать" ваш класс
    Cls = getattr(module, 'MyClass')  # Укажите имя вашего класса

__init_subclass__ для мониторинга появления новых потомков

Метод __init_subclass__ дает возможность в Python 3.6+ наблюдать за созданием новых подклассов и добавлять их в список:

Python
Скопировать код
class Base:
    kids = []  # Здесь будем хранить подклассы

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        Base.kids.append(cls)  # Как только найдено новое ниспоследование, добавляем его в список

Визуализация

Продемонстрируем поиск возможных "родственников" при помощи веселой и условной графической семейной диаграммы:

Семейное Древо (🌳): [Класс-Прародитель (💼)] / \ Класс-Родитель (📚) Класс-Дядя (🎩) / \ Класс-Ребёнок (🎓) Класс-Брат/Сестра (🏅)

Результаты поиска в рамках этой родословной:

Python
Скопировать код
import inspect
descendant_classes = [
    cls for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass)
    if issubclass(cls, globals()['Grandparent Class'])  # Здесь указатель на прародителя
]

У нас получилось собрать таких участников на семейном собрании: [📚, 🎩, 🎓, 🏅]

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

Отточите свои навыки до нового уровня с помощью следующих подходов:

  • Организовывайте "семейные встречи", используя методы класса.
  • Управляйте наследованием, переопределяя __subclasses__ в __init_subclass__.
  • Расширяйте количество подклассов, как настоящий проектировщик.
  • Старайтесь избегать использования eval, это опасно, как приглашать на праздник эксцентричного дядюшку.

Важные нюансы

Не забывайте, что даже в самой привычной обстановке могут возникнуть посторонние эффекты. Вот что стоит держать в уме:

  • В "семейный круг" включены классы, находящиеся в текущем пространстве имен.
  • Учитывайте динамические импорты для тех, кто может пропустить мероприятие.
  • Опираясь на vars(), вы можете собрать под окнами весь квартал.

Полезные материалы

  1. inspect — Инспекция живых объектов Python 3
  2. Метод разрешения заказов в Python – GeeksforGeeks
  3. Экземпляры, методы класса и статические методы – Real Python
  4. abc — Абстрактные базовые классы в Python 3
  5. Понимание метаклассов в Python | Ionel's Codelog
  6. Как найти все подклассы класса по его наименованию? – Stack Overflow
  7. Python: как выявить все классы, унаследованные от данного? – Stack Overflow