В любой сложной программе важно правильно организовать код: указать точку старта и разделить логические компоненты.
В языке Python модули могут быть не только выполнены самостоятельно, но и импортированы в другие модули. Поэтому хорошая программа должна уметь считывать контекст выполнения и менять логику работы в зависимости от окружения.
Подобное разделение рабочей и импортируемой частей позволяет избежать несвоевременного выполнения кода, а выделение единого начала работы программы упрощает настройку параметров запуска, передачу аргументов из командной строки и конфигурацию при тестировании. Когда вся важная логика сосредоточена в одном месте, добавлять автотесты и внедрять новые фичи становится гораздо удобнее.
Именно для этих целей в Python принято оформлять отдельную функцию, которая вызывается только при прямом запуске скрипта. Благодаря ней код становится чистым, модульным и контролируемым. Об этой функции, чаще именуемой main(), и пойдет речь в этой статье.
Важно отметить, что все демонстрируемые в этой статье примеры запускались с помощью интерпретатора Python версии 3.10.12, установленного на облачном сервере Timeweb Cloud под управлением операционной системы Ubuntu 22.04.
При этом каждый скрипт размещался в отдельном файле с расширением .py (например, script.py), после чего запускался с помощью команды интерпретатора Python:
Более того, логика работы скриптов реализована таким образом, чтобы их можно было без труда запустить в любом онлайн-компилятора Python для быстрой демонстрации их работы.
Облако на базе VMWare
в облаке на базе VMware. Изолированные ресурсы,
управление через vCloud Director, никаких затрат
на оборудование и лицензии.
Что такое функция main() в Python
Наипростейший код на Python может выглядеть так:
В другом случае код может последовательно выполняется на уровне файла скрипта:
Такая тривиальная организация логики подходит только для простых скриптов. Однако по мере роста сложности программы логическая путаница будет возрастать — код потребует реорганизации и порядка:
При большем количестве действий код будет выглядеть так:
У такой реализации есть несколько важных особенностей, которые необходимо рассмотреть подробнее.
Функция main()
Код с основной логикой программы размещается внутри отдельной функции. Не смотря на то, что ее имя может быть любым, принято использовать название «main» по аналогии с другими языками программирования — например, C, C++ или Java. Концепция такой реализации на Python называется «python main function».
Благодаря этому не только дополнительная, но и основная логика программы инкапсулирована — код находится не в голом виде на уровне файла, а в защищенном виде на уровне функции:
Таким образом функция main() выступает в качестве входной точки (entry point) в программу подобно тому, как это происходит во множестве других языков программирования.
Условие if __name__ == "__main__"
Перед вызовом функции main() следует условие if __name__ == "__main__" — странное с точки зрения вида и сложное с точки зрения записи. Однако оно необходимо для разделения логики запуска и импорта.
Смысл этой конструкции примерно такой: если скрипт запускается самостоятельно, то код внутри условия выполняется, а если скрипт импортируется, то код внутри условия игнорируется.
В данном случае под кодом внутри условия подразумевается вызов функции main():
При этом переменная __name__ является одним из встроенных dunder-переменных (double underscore) в языке Python — все они они берут свое название двойного подчеркивания с обеих сторон.
Иногда такие переменные называют «магическими» или «специальными». Подробнее о dunder-методах и dunder-переменных в языке Python можно узнать в отдельной статье Timeweb Cloud.
Все dunder-объекты определяются и используются языком Python для различных внутренних механизмов. Тем не менее обычный пользователь тоже имеет к ним доступ.
В зависимости от сценария переменная __name__ хранит разную информацию:
- Если модуль запущен как самостоятельная программа, то в
__name__записана строка__main__. - Если модуль импортирован из другого модуля через ключевое слово
import, то в__name__записано имя текущего модуля — того, что импортируется, а не того, что импортирует.
Таким образом dunder-переменная __name__ позволяет определить контекст в котором запускается определенный модуль.
Преимущества функции main()
Реализация, где логика программы находится внутри функции, а не на уровне файла, несет в себе ряд преимуществ как для разработки, так для использования.
Организация
Дополнительная (вспомогательные функции и классы) и основная (главная функция) логика обернуты в отдельные функции — их просто найти и легко читать. При этом глобальный код минимален — все, что не относится к инициализации, находится внутри функции, а не разбросано по всему модулю:
К тому же соблюдается единый стиль кода, в котором ни одна манипуляция с данными не выполняется на уровне файла. Благодаря этому в большом скрипте легко найти как место, где начинается выполнение скрипта, так и места, в которых выполняются дополнительные операции, обслуживающие основную логику программы.
Изоляция
Когда код пишется «в лоб» на уровне модуля, все временные переменные, файлы и подключения живут в глобальном пространстве имен, что затрудняет отладку и тестирование.
Если импортировать такой скрипт в другой модуль, глобальные переменные засорят его окружение:
Однако с функцией main() все переменные локальны — после завершения функции они уничтожаются, исключая риск утечки данных в глобальную область модуля:
Это особенно полезно во время тестирования, когда необходимо выборочно протестировать различные функции (в том числе и main()) без запуска кода, описывающего основную логику программы.
Безопасность
Без проверки dunder-переменной __name__ код на верхнем уровне модуля будет исполняться даже при импорте, что обычно не нужно и может вызвать побочные эффекты.
Например, может быть вспомогательный файл some.py:
И основной файл main.py:
Консольный вывод этого примера будет следующим:
Поэтому файл some.py должен выглядеть так:
Таким образом функция main() в сочетании с проверкой dunder-переменной __name__ защищает от непреднамеренного запуска кода из другого импортируемого модуля. Код становится безопасным.
Более того, внутри функции main() можно добавлять проверки контекста запуска, чтобы убедиться в наличие необходимых пользовательских прав и переменных окружения.
Как написать функцию main() в Python
Важно не забывать, что функция main() — не встроенная конструкция языка Python, а всего лишь обычная функция, которой дается роль точки входа в программу.
Поэтому, чтобы ее создать и гарантировать запуск только при непосредственном старте скрипта, необходимо выполнить три простых шага:
- Инструменты. Определить вспомогательные функции, содержащие бизнес‑логику.
- Логика. Объединить вспомогательные функции внутри
main(), выстроив последовательность действий, реализующих основную логику программы. - Проверка. Добавить проверку на контекст выполнения — самостоятельный запуск или импортирование модуля.
Такой шаблон делает код структурированным, безопасным при импорте и удобным для тестирования. Подобную реализацию можно считать отличной практикой для любых сложных реализаций на языке Python.
Пример программы с функцией main()
Для более глубокого понимания тех задач, которые решает функция main(), лучше всего рассмотреть более реальный пример кода на Python:
После запуска этого скрипта в консольном терминале появится сообщение, предлагающее ввести несколько строк с текстом:
Вводим первую строку и жмем клавишу Enter:
Потом вводим вторую строку и снова жмем клавишу Enter:
Далее вводим третью строку и жмем клавишу Enter два раза:
После этого в консольном терминале появится сообщение с подробным отчетом о введенном тексте:
Если же эту программу, размещенную в файле program.py, импортировать в другой скрипт Python, то выполнится только тот код, который размещен вне функции main():
Консольный вывод будет следующим:
Таким образом относительно сложная программа, производящая статистический анализ введенного текста, имеет и четкое разделение логики, и определение внешнего контекста выполнения.
Когда использовать функцию main(), а когда — нет
Использовать функцию main() и проверку по __name__ стоит только тогда, когда необходимо получить преимущества структурирования, изоляции и контроля исполнения. Однако в ряде случаев ее можно опустить ради простоты.
Когда стоит (и почти всегда уместно) использовать функцию main():
- Скрипты средней и большой сложности. Если в программе относительно большой объем кода с нетривиальной логикой, опирающейся сразу на несколько функций и классов.
- Библиотеки и утилиты с экспортируемым API. Когда необходимо, чтобы часть функций модуля была доступна для импорта в другие проекты без запуска побочных действий.
- Наличие автотестов. Если необходимо покрыть тестами только чистую логику без вспомогательных функций, используемых в этой логике.
Когда можно обойтись без функции main():
- Простые однотипные скрипты. Когда логика тривиально или выполняется однократно для быстрого преобразования данных.
- Учебные примеры и демо‑фрагменты. Когда иллюстрируется несколько приемов Python‑синтаксиса в целях обучения.
Говоря проще, если программа на Python — самостоятельная утилита или приложение с несколькими этапами обработки, аргументами командной строки и подключениями к ресурсам — можно смело вводить функцию main().
Если же программа — небольшой одноразовый скрипт, то можно обойтись без функции main() ради сохранения лаконичности и компактности кода.
Подготовили для вас выгодные тарифы на облачные серверы
477 ₽/мес
657 ₽/мес
Заключение
Функция main() в языке программирования Python выполняет две важные функции:
- Изолирует основную логику программы от глобального пространства имен.
- Разделяет логику самостоятельного запуска от логики импорта.
Таким образом, код на Python из простого скрипта с последовательно выполняемыми действиями превращается в полноценную программу с точкой входа, инкапсулированной логикой и способностью анализировать среду выполнения.
