Получение списка всех классов в текущем модуле Python
Быстрый ответ
Чтобы аккуратно получить все классы, определенные в вашем модуле, используйте модули inspect
и sys
следующим образом:
import inspect, sys
classes = [cls for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass) if cls.__module__ == __name__]
Не забудьте предварительно подключить модули inspect
и sys
. Таким образом мы отсечем классы, импортированные в модуль из других источников.
Подробный разбор кода
Давайте подробно разберем этот метод, чтобы лучше понять, как работают в паре модули inspect
и sys
.
Альтернатива: функция globals()
Мы также можем прибегнуть к методу globals()
— этой функции, которая возвращает словарь глобальных атрибутов модуля:
classes = [global_ for global_ in globals().values()
if inspect.isclass(global_) and global_.__module__ == __name__]
Этот метод позволяет отфильтровать список глобальных объектов модуля, оставив только классы, определенные непосредственно в нем.
Альтернатива: функция dir()
Еще один способ — это использование функции dir()
, которая возвращает полный список имен, определенных в модуле. Чтобы из него извлечь имена классов, воспользуйтесь следующим кодом:
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()
и аналогичными методами, важно всегда оперировать копией данных, чтобы избежать нежелательных побочных эффектов:
for name, obj in globals().copy().items():
if inspect.isclass(obj) and obj.__module__ == __name__:
# Ваши действия...
Полезные практические советы
Обработка ошибок: ваш страховой полис
Обязательно используйте обработку исключений для того, чтобы ваш код оставался рабочим даже в случае внезапных ошибок:
try:
# здесь работает ваш код
except Exception as error:
print(f"Произошла ошибка: {error}")
Дополнительное средство: itertools.chain()
Если вам потребуется взаимодействовать с несколькими модулями сразу или перечислить классы разных модулей, используйте itertools.chain
:
import itertools
modules = [sys.modules[__name__], другой_модуль]
classes = list(itertools.chain.from_iterable(
inspect.getmembers(module, inspect.isclass) for module in modules
))
Благодаря itertools
, все нужные вам классы соберутся в один общий список.
Кроссплатформенность: как гарантировать совместимость кода
Уверьтесь, что ваш код корректно работает в разных средах исполнения. Ваш код должен быть кроссплатформенным.
Атрибут module: универсальный индикатор
Атрибут __module__
позволяет точно узнать, из какого модуля был вызван класс:
# с помощью '__module__' можно проследить источник класса
Визуализация
Представим, что мы великий маг, окруженный бесчисленным количеством магических свитков, но нам нужны только те, которые написаны конкретным автором. Мы находимся в секции 'Python Module', в поисках свитков 'Мастера классов':
Секция волшебной библиотеки: Модуль Python 📚
В поисках трудов: Мастер Классов 🖊️
Следующий метод поможет нам найти нужные свитки:
import sys
свитки_мастера = [name for name, obj in sys.modules[__name__].__dict__.items()
if isinstance(obj, type) and obj.__module__ == __name__]
Открытые свитки 📚🧐: [КлассВидящего, КлассЗачарователя, КлассАлхимика]
Этот метод напоминает поиск книг по меткам на книжной полке: он проходит по всем классам, определенным в текущем модуле.
Будьте осторожны!
Глобальные переменные: несусветная опасность
Будьте внимательны с globals()
, так как его содержимое может изменяться в реальном времени. По возможности, работайте с его копией:
globals_copy = globals().copy()
Загрязнение пространства имен: не создайте себе проблем
Избыток объектов в пространстве имен может породить ошибки. Используйте __module__
, чтобы держать то, что вокруг вас, под контролем.
Dir() — это всего лишь имена
Функция dir()
возвращает список имен, но дальше нужно использовать getattr()
, чтобы получить доступ к объектам, которые эти имена представляют.
Использование модуля pyclbr для извлечения классов
Модуль pyclbr
позволяет найти все имена классов в .py
-файле. Обратите внимание, что он не применим в интерактивном режиме:
import pyclbr
названия_классов = list(pyclbr.readmodule(__name__).keys())
С помощью pyclbr
можно получить имена классов без необходимости заниматься интроспекцией объектов.
Полезные материалы
- inspect — инструмент для инспекции live объектов — Документация Python 3.12.2 — подробнее о модуле inspect.
- inspect — инспекция live объектов — PyMOTW 3 — описание модуля inspect.
- За какими функциями стоит следить в Python – Real Python — статья о значении и использовании
__main__
иif __name__ == "__main__"
в Python. - Глоссарий – Руководство пользователя по пакетированию в Python — освещает различия между модулями и пакетами в Python.
- Medium — обсуждается работа с модулем inspect в Python.