Конструкция if __name__ == "__main__" определяет точку входа Python-программы: она помогает отличить прямой запуск файла от его импорта как модуля и не выполнять основной сценарий случайно.
if __name__ == "__main__":
main()
Она отделяет описание программы — константы, классы и функции — от её запуска.
Название может выглядеть необычно, но это не специальная команда и не обязательное имя функции. Здесь сравниваются две обычные строки, а main() — функция, которую автор программы решил использовать как основной сценарий.
Как Python выполняет файл
Python читает модуль сверху вниз. Импорт, присваивание и вызов функции выполняются сразу:
print("Модуль загружается")
def greet():
print("Привет")
greet()
И print(), и greet() сработают при прямом запуске и при импорте. Определение def greet(): лишь создаёт функцию, но строка greet() уже вызывает её.
Защитный блок позволяет выполнить вызов только при прямом запуске:
def greet():
print("Привет")
if __name__ == "__main__":
greet()
Что хранится в name
Python автоматически создаёт переменную __name__ для каждого модуля.
Если запустить файл напрямую:
python main.py
то внутри него:
__name__ == "__main__"
Если тот же файл импортировать:
import main
то __name__ содержит имя модуля — "main". Условие ложно, поэтому программа не запускается сама.
Можно увидеть разницу самостоятельно:
print(__name__)
python main.py
# __main__
python -c "import main"
# main
Зачем нужна функция main()
def load_data():
return [1, 2, 3]
def main():
data = load_data()
print(data)
if __name__ == "__main__":
main()
При python main.py вызывается main(). При import main функции становятся доступны другому файлу или тесту, но print() не выполняется.
Это особенно важно, если программа:
- отправляет API-запрос;
- читает
input(); - запускает бесконечное меню;
- создаёт или удаляет файл;
- изменяет данные во внешнем сервисе.
Импорт такого модуля не должен сам выполнять эти действия.
Что такое побочный эффект
Побочный эффект — действие, которое меняет состояние программы или внешнего мира. Например:
response = requests.get(API_URL)
answer = input("Выбери пункт: ")
Path("result.json").write_text("{}")
Если эти строки находятся на верхнем уровне, они выполняются сразу при import. Тест может неожиданно обратиться к сети, другой модуль — ждать пользовательский ввод, а импорт утилиты — создать файл.
Вызовы переноси в функции и запускай из main():
def main():
response = requests.get(API_URL, timeout=10)
print(response.status_code)
if __name__ == "__main__":
main()
Сам импорт requests, объявление API_URL и определение main() безопасны: сетевой запрос начнётся только при вызове функции.
Временный код во время разработки
Пока полноценной main() ещё нет, тестовый запуск тоже помещай под защиту:
if __name__ == "__main__":
try:
print(load_data())
except ValueError as error:
print(f"Ошибка: {error}")
Позже временный код заменяется окончательной точкой входа:
def main():
# основной сценарий программы
...
if __name__ == "__main__":
main()
Так промежуточный файл можно импортировать в тестах уже во время разработки.
Что можно оставить вне блока
Вне точки входа обычно находятся:
import os
API_URL = "https://example.com/api"
def fetch_data():
...
Импорты, константы и определения функций лишь подготавливают модуль. Вызовы, которые запускают сценарий, находятся внутри main() или защищённого блока.
Загрузка настроек тоже часто остаётся снаружи, если она только читает локальные значения:
load_dotenv()
API_KEY = os.getenv("API_KEY")
Но проверку ключа и сетевой запрос лучше выполнять внутри функций, вызванных из main(). Тогда --help, тесты и импорт вспомогательных функций смогут работать без обращения к API.
Точка входа в проекте из нескольких файлов
Представь структуру:
weather_app/
├── main.py
├── api.py
└── formatting.py
api.py предоставляет функции:
def get_weather(city):
...
main.py собирает сценарий:
from api import get_weather
def main():
city = input("Город: ").strip()
weather = get_weather(city)
print(weather)
if __name__ == "__main__":
main()
Теперь api.py можно переиспользовать в другом интерфейсе, например в Telegram-боте или веб-приложении, не запуская консольный ввод.
Точка входа и argparse
Разбор аргументов тоже является частью запуска программы:
import argparse
def build_parser():
parser = argparse.ArgumentParser()
parser.add_argument("name")
return parser
def main():
args = build_parser().parse_args()
print(f"Привет, {args.name}!")
if __name__ == "__main__":
main()
build_parser() можно импортировать и тестировать отдельно. parse_args() выполняется только при запуске программы и не пытается разобрать аргументы тестовой среды во время импорта.
Почему это помогает тестам
# main.py
def calculate_total(prices):
return sum(prices)
def main():
print(calculate_total([10, 20, 30]))
if __name__ == "__main__":
main()
Тест безопасно импортирует функцию:
from main import calculate_total
def test_calculate_total():
assert calculate_total([10, 20, 30]) == 60
Во время импорта итог не печатается, ввод не запрашивается и внешние сервисы не вызываются.
Частые ошибки
Неправильное имя переменной:
if name == "main":
main()
Правильно — по два подчёркивания с каждой стороны:
if __name__ == "__main__":
main()
Не вызывай функцию сразу в условии:
# Неправильно
if __name__ == "__main__":
main
Для запуска нужны скобки: main().
Ещё одна ошибка — вызвать main() до проверки:
# Неправильно: выполнится и при импорте
main()
if __name__ == "__main__":
main()
Оставь только защищённый вызов.
Также не помещай внутрь блока определения всех функций:
# Неудачно: greet не существует при import main
if __name__ == "__main__":
def greet():
return "Привет"
Определи функцию снаружи, а внутри блока только вызови её.
Нужно ли всегда использовать этот блок
Для короткого одноразового файла из двух строк он не обязателен. Но блок стоит использовать, если код:
- состоит из нескольких функций;
- будет импортироваться или тестироваться;
- работает с API, файлами или пользовательским вводом;
- имеет CLI или меню;
- может позже стать частью более крупного проекта.
Это небольшая привычка, которая делает модуль безопаснее для переиспользования.
Короткая проверка
Создай main.py:
def greet():
return "Привет"
def main():
print(greet())
if __name__ == "__main__":
main()
Проверь два сценария:
python main.py
python -c "import main; print(main.greet())"
В первом случае запускается программа. Во втором импорт сам ничего не печатает — вывод появляется только из явно вызванной greet().
Итоговая схема проста:
прямой запуск → __name__ равно "__main__" → main() выполняется
импорт → __name__ равно имени модуля → main() не выполняется
💬 Комментарии (0)
Комментариев пока нет
Станьте первым, кто поделится мнением об этой статье!