← Назад к вопросам

Что будет если выполнить python -m и код?

1.8 Middle🔥 161 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Выполнение Python кода через флаг -m

Основная концепция

Команда python -m используется для выполнения модуля как скрипта. При этом Python:

  1. Находит модуль в sys.path
  2. Выполняет его содержимое как основную программу (__name__ == "__main__")
  3. Добавляет текущую директорию в sys.path

Это отличается от простого вызова python script.py, хотя результаты часто похожи.

Синтаксис и примеры

Базовый синтаксис:

# python -m module_name [args]
# python -m package.submodule [args]

Примеры использования:

# Запуск модуля из стандартной библиотеки
python -m http.server 8000

# Запуск пакета с __main__.py
python -m my_package

# Запуск модуля с аргументами
python -m json.tool input.json

# Запуск pytest
python -m pytest tests/

# Запуск pip
python -m pip install requests

Что происходит при выполнении python -m?

# Представим, что у нас есть модуль: mypackage/mymodule.py
print(f"Module name: {__name__}")
print(f"Module file: {__file__}")
print(f"sys.path[0]: {__import__(sys).path[0]}")

# Запуск через: python -m mypackage.mymodule
# Вывод:
# Module name: __main__
# Module file: /full/path/to/mypackage/mymodule.py
# sys.path[0]: /current/working/directory

# Запуск через: python mypackage/mymodule.py
# Вывод (по сути то же самое!):
# Module name: __main__
# Module file: mypackage/mymodule.py
# sys.path[0]: /current/working/directory

Различия между способами запуска

1. python -m модуль (рекомендуется)

# Файл: mypackage/app.py
import sys
print(f"__name__: {__name__}")
print(f"__package__: {__package__}")
print(f"sys.path[0]: {sys.path[0]}")

# Команда: python -m mypackage.app
# __name__: __main__
# __package__: mypackage
# sys.path[0]: (current directory)

2. python script.py (прямой запуск)

# Команда: python mypackage/app.py
# Проблема: если app.py импортирует из своего пакета
# from . import other_module  # ImportError!
# Потому что Python не знает, что это часть пакета

Когда использовать -m?

Сценарий 1: Пакеты с зависимостями от структуры

# mypackage/__main__.py
from . import core
from . import utils

if __name__ == "__main__":
    core.run()

# Правильно: python -m mypackage
# Неправильно: python mypackage/__main__.py

Сценарий 2: Использование относительных импортов

# mypackage/handlers/auth.py
from ..utils import validate  # Относительный импорт
from ..models import User     # Работает только в контексте пакета

# python -m mypackage.handlers.auth ✓ Работает
# python mypackage/handlers/auth.py ✗ ImportError

Сценарий 3: Встроенные модули и утилиты

# Эти команды работают только через -m:
python -m http.server 8000       # Простой веб-сервер
python -m json.tool file.json    # Форматирование JSON
python -m venv venv              # Создание virtual environment
python -m pip install package    # Установка пакетов
python -m pytest                 # Запуск тестов

Важные различия в sys.path

import sys

def show_path():
    print("sys.path:")
    for i, path in enumerate(sys.path):
        print(f"  [{i}] {path}")

# Запуск 1: python -m myapp
# sys.path[0] == (текущая директория)
# Может импортировать из текущей директории

# Запуск 2: python /path/to/script.py
# sys.path[0] == /path/to (директория скрипта)
# Может импортировать только из директории скрипта

Практический пример: правильная структура пакета

# project/
# ├── myapp/
# │   ├── __init__.py
# │   ├── __main__.py        # Точка входа
# │   ├── core.py
# │   └── utils.py
# └── setup.py

# myapp/__main__.py
from . import core
import sys

if __name__ == "__main__":
    print(f"Запущено как: python -m myapp")
    print(f"Текущий пакет: {__package__}")
    core.main()

# myapp/core.py
from . import utils

def main():
    result = utils.process()
    print(f"Result: {result}")

# Запуск:
# $ cd project
# $ python -m myapp  ✓ Правильно
# $ python myapp/__main__.py  ✗ Неправильно

Ошибки, которые возникают

# Ошибка 1: ImportError при прямом запуске
# python myapp/core.py
# from . import utils  # ModuleNotFoundError: __package__ is None

# Решение: python -m myapp.core

# Ошибка 2: Различные sys.path
# Может привести к импорту разных версий модулей

# Ошибка 3: __name__ != __main__
# if __name__ == __main__:  # Не выполнится, если модуль импортирован

Выводы

  1. python -m находит и выполняет модуль через систему импорта Python
  2. Правильный выбор между -m и прямым запуском зависит от структуры проекта
  3. Используй -m для пакетов с относительными импортами
  4. Используй -m для встроенных утилит (http.server, pytest, pip)
  5. package содержит имя пакета при использовании -m
  6. sys.path[0] при -m указывает на текущую директорию, что часто более предсказуемо
  7. Best practice: используй python -m package_name вместо прямого запуска скриптов для больших проектов
Что будет если выполнить python -m и код? | PrepBro