Получение списка всех классов в текущем модуле Python

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

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

Чтобы аккуратно получить все классы, определенные в вашем модуле, используйте модули inspect и sys следующим образом:

Python
Скопировать код
import inspect, sys

classes = [cls for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass) if cls.__module__ == __name__]

Не забудьте предварительно подключить модули inspect и sys. Таким образом мы отсечем классы, импортированные в модуль из других источников.

Кинга Идем в IT: пошаговый план для смены профессии

Подробный разбор кода

Давайте подробно разберем этот метод, чтобы лучше понять, как работают в паре модули inspect и sys.

Альтернатива: функция globals()

Мы также можем прибегнуть к методу globals() — этой функции, которая возвращает словарь глобальных атрибутов модуля:

Python
Скопировать код
classes = [global_ for global_ in globals().values()
           if inspect.isclass(global_) and global_.__module__ == __name__]

Этот метод позволяет отфильтровать список глобальных объектов модуля, оставив только классы, определенные непосредственно в нем.

Альтернатива: функция dir()

Еще один способ — это использование функции dir(), которая возвращает полный список имен, определенных в модуле. Чтобы из него извлечь имена классов, воспользуйтесь следующим кодом:

Python
Скопировать код
classes = [getattr(sys.modules[__name__], name) for name in dir(sys.modules[__name__])
           if inspect.isclass(getattr(sys.modules[__name__], name)) and getattr(sys.modules[__name__], name).__module__ == __name__]

Здесь dir() дает нам список имен, а getattr() преобразует имена в сами объекты, соответствующие определениям классов в вашем модуле.

Внимательно: с globals() и подобными нужно быть аккуратным!

Работая с globals() и аналогичными методами, важно всегда оперировать копией данных, чтобы избежать нежелательных побочных эффектов:

Python
Скопировать код
for name, obj in globals().copy().items():
    if inspect.isclass(obj) and obj.__module__ == __name__:
        # Ваши действия...

Полезные практические советы

Обработка ошибок: ваш страховой полис

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

Python
Скопировать код
try:
    # здесь работает ваш код
except Exception as error:
    print(f"Произошла ошибка: {error}")

Дополнительное средство: itertools.chain()

Если вам потребуется взаимодействовать с несколькими модулями сразу или перечислить классы разных модулей, используйте itertools.chain:

Python
Скопировать код
import itertools

modules = [sys.modules[__name__], другой_модуль]
classes = list(itertools.chain.from_iterable(
    inspect.getmembers(module, inspect.isclass) for module in modules
))

Благодаря itertools, все нужные вам классы соберутся в один общий список.

Кроссплатформенность: как гарантировать совместимость кода

Уверьтесь, что ваш код корректно работает в разных средах исполнения. Ваш код должен быть кроссплатформенным.

Атрибут module: универсальный индикатор

Атрибут __module__ позволяет точно узнать, из какого модуля был вызван класс:

Python
Скопировать код
# с помощью '__module__' можно проследить источник класса

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

Представим, что мы великий маг, окруженный бесчисленным количеством магических свитков, но нам нужны только те, которые написаны конкретным автором. Мы находимся в секции 'Python Module', в поисках свитков 'Мастера классов':

Markdown
Скопировать код
Секция волшебной библиотеки: Модуль Python 📚
В поисках трудов: Мастер Классов 🖊️

Следующий метод поможет нам найти нужные свитки:

Python
Скопировать код
import sys

свитки_мастера = [name for name, obj in sys.modules[__name__].__dict__.items()
                 if isinstance(obj, type) and obj.__module__ == __name__]

Открытые свитки 📚🧐: [КлассВидящего, КлассЗачарователя, КлассАлхимика]

Этот метод напоминает поиск книг по меткам на книжной полке: он проходит по всем классам, определенным в текущем модуле.

Будьте осторожны!

Глобальные переменные: несусветная опасность

Будьте внимательны с globals(), так как его содержимое может изменяться в реальном времени. По возможности, работайте с его копией:

Python
Скопировать код
globals_copy = globals().copy()

Загрязнение пространства имен: не создайте себе проблем

Избыток объектов в пространстве имен может породить ошибки. Используйте __module__, чтобы держать то, что вокруг вас, под контролем.

Dir() — это всего лишь имена

Функция dir() возвращает список имен, но дальше нужно использовать getattr(), чтобы получить доступ к объектам, которые эти имена представляют.

Использование модуля pyclbr для извлечения классов

Модуль pyclbr позволяет найти все имена классов в .py-файле. Обратите внимание, что он не применим в интерактивном режиме:

Python
Скопировать код
import pyclbr

названия_классов = list(pyclbr.readmodule(__name__).keys())

С помощью pyclbr можно получить имена классов без необходимости заниматься интроспекцией объектов.

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

  1. inspect — инструмент для инспекции live объектов — Документация Python 3.12.2 — подробнее о модуле inspect.
  2. inspect — инспекция live объектов — PyMOTW 3 — описание модуля inspect.
  3. За какими функциями стоит следить в Python – Real Python — статья о значении и использовании __main__ и if __name__ == "__main__" в Python.
  4. Глоссарий – Руководство пользователя по пакетированию в Python — освещает различия между модулями и пакетами в Python.
  5. Medium — обсуждается работа с модулем inspect в Python.