Главный модуль Python: __main__

Раздел: Python -> Структура модулей

Основные подходы к использованию __main__

Как организовать выполнение кода только при прямом запуске скрипта?

Самое эффективное решение - использование условной конструкции if __name__ == "__main__":. Эта проверка позволяет отделить код, который выполняется при импорте модуля, от кода, который запускается только при вызове файла как основного скрипта.


# mymodule.py
def greet(name):
    return f"Привет, {name}!"

if __name__ == "__main__":
    print(greet("Мир"))

Python module naming (соглашения об именовании модулей python)

При запуске скрипта python mymodule.py будет выведено "Привет, Мир!". Если же модуль импортировать в другой файл (import mymodule), то функция greet будет доступна, но код внутри блока if не выполнится.

Типичные ошибки:

  • Забыть добавить условие - тогда код запускается при любом импорте.
  • Опечатки в имени __main__ (два подчёркивания с обеих сторон).
  • Рекурсивный импорт при наличии в блоке импорта того же модуля.

Как сделать, чтобы код выполнялся только при импорте, а не при запуске?

Иногда нужно, наоборот, выполнять код только при импортировании модуля. Для этого можно проверить if __name__ != "__main__":. Однако такое встречается редко. Чаще используется для инициализации модуля при его загрузке.


# setup.py
print("Модуль загружен")
if __name__ != "__main__":
    print("Этот код выполняется при импорте")

Python modules (модули python)

Цель:

Инициализация глобальных переменных или регистрация компонентов при импорте.

Как передать аргументы командной строки в основной модуль?

В блоке if __name__ == "__main__": можно вызвать функцию с аргументами из sys.argv или использовать argparse.


# calc.py
import sys

def add(a, b):
    return a + b

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Использование: python calc.py число1 число2")
    else:
        result = add(float(sys.argv[1]), float(sys.argv[2]))
        print(f"Результат: {result}")

Python module main (основной модуль __main__)

При запуске python calc.py 5 3 выведет "Результат: 8.0".

Проблема:

Незащищённый доступ к sys.argv может привести к ошибкам при отсутствии аргументов. Рекомендуется использовать argparse.

Как использовать __main__.py в пакете для создания точки входа?

Если модуль представляет собой пакет (директорию с __init__.py), можно добавить файл __main__.py. При запуске пакета через python -m mypackage выполнится код из __main__.py.


# mypackage/__main__.py
def main():
    print("Запущен пакет mypackage")

if __name__ == "__main__":
    main()

Запуск: python -m mypackage выведет "Запущен пакет mypackage".

Сценарий использования:

Пакеты, которые можно запускать как скрипты, например, для утилит командной строки.

Как организовать тестирование внутри модуля при прямом запуске?

В блоке if __name__ == "__main__": можно вызывать тесты, например, с помощью unittest.main() или doctest.testmod().


# test_demo.py
import doctest

def factorial(n):
    """Возвращает факториал числа n.
    >>> factorial(5)
    120
    """
    if n == 0:
        return 1
    return n * factorial(n-1)

if __name__ == "__main__":
    doctest.testmod(verbose=True)

При запуске скрипта будут выполнены doctest-тесты и показан результат.

Расширенные примеры использования __main__

Пример 1: Обработка аргументов с argparse

Пример

# greeter.py
import argparse

def greet(name, greeting="Привет"):
    return f"{greeting}, {name}!"

def main():
    parser = argparse.ArgumentParser(description="Простой приветственный скрипт")
    parser.add_argument("name", help="Имя для приветствия")
    parser.add_argument("-g", "--greeting", default="Привет", help="Приветствие (по умолчанию 'Привет')")
    args = parser.parse_args()
    print(greet(args.name, args.greeting))

if __name__ == "__main__":
    main()

Запуск:

$ python greeter.py Мир -g Здравствуйте
Здравствуйте, Мир!

Пример 2: Пакет с __main__.py и изучением атрибутов модуля

Пример

# mypackage/__init__.py
# пустой файл

# mypackage/__main__.py
import sys

def main():
    print("Модуль __main__ выполнен")
    print("Аргументы:", sys.argv[1:] if len(sys.argv) > 1 else "нет")
    print("Значение __name__:", __name__)

if __name__ == "__main__":
    main()

Запуск:

$ python -m mypackage --test
Модуль __main__ выполнен
Аргументы: ['--test']
Значение __name__: __main__

Пример 3: Логирование при запуске

Пример

# logger_demo.py
import logging

def setup_logging(level=logging.INFO):
    logging.basicConfig(level=level, format="%(asctime)s - %(levelname)s - %(message)s")

def do_work():
    logging.info("Выполнение работы")

if __name__ == "__main__":
    setup_logging()
    do_work()

Результат:

2025-03-27 12:00:00,000 - INFO - Выполнение работы

Пример 4: Встроенное тестирование с unittest

Пример

# calculator.py
import unittest

def add(a, b):
    return a + b

class TestCalculator(unittest.TestCase):
    def test_add(self):
        self.assertEqual(add(2, 3), 5)

if __name__ == "__main__":
    unittest.main()

Результат:

.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

Пример 5: Модуль с режимом разработки и продакшн

Пример

# config_demo.py
import os

def load_config():
    return {"debug": os.getenv("DEBUG", "false").lower() == "true"}

def run():
    config = load_config()
    if config["debug"]:
        print("Режим отладки включен")
    else:
        print("Продакшн режим")

if __name__ == "__main__":
    run()

Запуск с переменной окружения:

$ DEBUG=true python config_demo.py
Режим отладки включен

Основной модуль __main__ - comments

En
Python module main (python)