Python: Настройка окружения
2026-02-26 23:10 Diff

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

Точка входа для приложения

Большинство приложений — это достаточно объемный проект, состоящий из множества модулей. Но когда запускается приложение, то запускается какой-то один конкретный исполняемый файл, он называется точкой входа:

Выше пример небольшого проекта из двух файлов:

  • my_application/module.py — определена функция, выводящая сообщение в консоль
  • my_application/scripts/main.py — импортируется и вызывается функция

Модуль main.py в таком проекте является точкой входа. Точку входа, как и прочие исполняемые файлы, принято располагать в директории scripts. А сами исполняемые файлы часто называют скриптами. Также принято все необходимые вызовы делать внутри main(), функции без аргументов. И уже вызывая эту функцию, мы запускаем приложение.

В примере выше мы вызываем Python из окружения проекта командой uv run. Флаг -m означает "вызвать файл как модуль". В таком случае, Python осведомлен, что вызываемый файл не одиночный скрипт, а часть проекта с импортами из других модулей. Путь до модуля нужно передавать в формате через точку, начиная от корня проекта.

Специальная переменная __name__

В проекте бывают несколько точек входа. Каждая может работать как отдельное приложение и при этом использовать общую логику. Обычно в точке входа происходит вызов одной функции. Могут быть исключения, но всегда лучше стремиться к вызову одной единственной функции.

Создадим еще один скрипт и импортируем в него предыдущий:

Запустим его:

Сообщение вывелось дважды. Почему так? Чтобы импортировать функцию из модуля, интерпретатор читает и загружает модуль полностью. В этот момент будут выполнены все определения и вызовы на уровне модуля. А значит, импортируя первый скрипт во второй, мы еще раз вызовем функцию main(). Выходит, нам нужно как-то различать ситуации двух типов:

  • Модуль работает как скрипт — выполняем вызовы
  • Модуль импортируетс�� — не выполняем вызовы

Для решения этой задачи мы можем воспользоваться специальной переменной __name__. Это одна из многих специальных переменных, которые загружаются интерпретатором на старте.

Кажется, что у переменной необычное имя — в нем целых четыре символа подчеркивания. На самом деле такие имена часто встречаются в Python-коде и как правило имеют какой-то специальный смысл. Опытный разработчик обычно помнит наизусть пару десятков таких переменных, поэтому про эти переменные любят спрашивать на собеседованиях.

Посмотрим, что хранит переменная __name__ в каждом конкретном случае:

  • Если происходит запуск в качестве скрипта, то переменная получает специальное значение — строку '__main__'
  • Если происходит обычный импорт, то эта переменная содержит полное имя модуля

Проверив значение этой переменной, мы можем отличить запуск в качестве скрипта от импортирования. Перепишем первый скрипт main.py с применением этого нового знания:

И проверим:

Сообщение вывелось один раз, ведь условие if __name__ == "__main__": при импорте не выполнится, и функция main() не вызовется.

Изначальный скрипт тоже работает как полагается:

uv и точка входа

Каждый раз вводить полное имя модуля довольно затратно, да и неправильно. Пользователь нашей программы не должен знать о ее внутреннем устройстве, о структуре файлов. Должна быть короткая команда для запуска программы. uv предоставляет возможность указать точку входа проекта, после чего его можно запускать одной командой uv run <точка-входа>.

Для начала нужно отредактировать файл конфигурации проекта pyproject.toml:

Мы добавляем две группы секции. Первая, [build-system] и [XX.build.targets.wheel] указывает менеджеру, что наш проект это пакет со своими импортами и точкой входа. При следующем запуске, uv также установит наш проект в виртуальное окружение.

Вторая группа, [project.scripts] указывает на точки входа в проекте. Название точки записывается через дефис. А путь до нее указывается как полный путь, через точку, до скрипта и после двоеточия сама функция запуска.

Теперь мы можем запустить проект короткой командой uv run <точка-входа>:

Точка входа для библиотеки

Если в приложениях точкой входа является место, где происходит вызов самого приложения в виде функции или какого-то кода, то для библиотек ситуация иная. В библиотеках мы не должны в обычной ситуации вызывать код. Библиотека предоставляет функцию или набор функций, а когда их вызывать решает тот, кто импортирует библиотеку в свой модуль.

Например, библиотека more-itertools предоставляет различный набор вспомогательных функций. Мы можем импортировать любое количество функций из этой библиотеки, и сами решать какую когда использовать:

Когда мы указываем подобный импорт, мы не указываем путь до конкретного файла, откуда нужно импортировать функцию, а только указываем название библиотеки. Но как тогда интерпретатор узнает где находится нужная нам функция? Для решения, нам нужно экспортировать "наружу", на верхний уровень библиотеки необходимые функции или целые модули. В этом нам понадобится файл __init__.py

Обычная задача модуля __init__.py в том, чтобы указывать интерпретатору, что директория с файлами это пакет, чтобы он мог разруливать импорты. Но также в нем можно перечислить все функции, что мы хотим экспортировать наружу. Добавим в __init__.py нашего проекта запись:

Сперва мы импортируем необходимые нам функции или целые модули. Затем вписываем кортеж из них в еще одну особую переменную __all__. Теперь, тем, кто будет использовать эту библиотеку, не нужно знать в каком файле определены функции. При импорте нашей библиотеки, экспортируется все перечисленное в __all__.

Подобный файл с экспортами функций и модулей для пользования нашей библиотекой называют фасадом.

Итог

Мы познакомились с точками входа для приложений и библиотек. Разобрали, что для приложений точка входа является местом, где начинается выполнение кода, а для библиотек это модуль __init__.py с экспортом сущностей. Все, что мы обсудили, тесно связано с проектированием проекта и позволит заложить фундамент хорошей архитектуры для сложных проектов.