Несколько файлов с кодом соединены в одну программу Python
Программирование

Модули и import в Python: как разделить программу на файлы

Разбираем, что Python называет модулем, как работает import, зачем нужен __name__ и почему код не должен запускать работу при импорте.

Содержание

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

Модуль решает эту проблему без новой технологии. В простом проекте модуль — обычный файл с расширением .py. Его функции и переменные можно подключить к другому файлу оператором import.

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

Что стоит выносить в отдельный файл

Граница модуля должна следовать назначению кода. Функции форматирования отчёта можно хранить вместе, работу с файлами — в другом модуле, а запуск программы — в коротком основном файле. Не нужно создавать новый файл для каждой функции: десятки крошечных модулей так же мешают чтению, как один огромный.

Для примера сделаем программу из двух файлов. Создайте на локальном компьютере каталог server-report. В нём должна получиться такая структура:

server-report/
├── formatters.py
└── report.py

formatters.py будет хранить преобразование данных, а report.py — передавать исходные значения и печатать готовую строку. Оба файла находятся рядом, поэтому Python сможет найти модуль без дополнительной настройки путей.

Импортируйте модуль под его именем

Поместите в formatters.py функцию, которая превращает имя сервера и результат проверки в строку отчёта:

def format_status(hostname, is_available):
    state = "доступен" if is_available else "не отвечает"
    return f"{hostname}: {state}"

Здесь условное выражение выбирает один из двух текстов, а функция возвращает результат через return. Файл ничего не печатает и не обращается к сети: он только определяет действие, которое сможет вызвать основной модуль.

Теперь сохраните в соседнем report.py импорт и вызов функции:

import formatters


message = formatters.format_status("example.com", True)
print(message)

Запустите python report.py из каталога server-report. В терминале появится example.com: доступен. Запись formatters.format_status сразу показывает, где определена функция. Если Python сообщает ModuleNotFoundError, проверьте имя файла, расширение и текущий каталог, из которого запускается команда.

from import сокращает запись, но скрывает источник имени

В качестве альтернативы измените report.py так, чтобы подключить конкретную функцию напрямую и вызывать её без префикса модуля:

from formatters import format_status


message = format_status("example.com", False)
print(message)

Результатом будет example.com: не отвечает. Такой импорт уместен, когда происхождение имени ясно и оно не совпадает с локальной функцией. В большом файле вариант import formatters обычно читается легче: префикс остаётся рядом с каждым вызовом.

Не используйте from formatters import * в рабочем коде. Звёздочка добавляет сразу много имён, но читатель не видит их список в месте импорта. Совпадение с уже существующим именем может изменить поведение программы без явной ошибки.

Импорт выполняет верхний уровень файла

Python выполняет инструкции модуля при его первом импорте в текущем процессе. Определение функции при этом создаёт функцию, но не вызывает её. А вот print(), чтение файла или сетевой запрос на верхнем уровне начнут работу сразу.

Основной запуск лучше оформить функцией main. Обновите report.py следующим образом:

import formatters


def main():
    message = formatters.format_status("example.com", True)
    print(message)


if __name__ == "__main__":
    main()

Когда файл запущен командой python report.py, специальная переменная __name__ равна "__main__", поэтому функция вызывается. При import report значение будет "report", и программа не напечатает отчёт сама. Это позволяет позже импортировать main или другие функции в тестах без нежелательных действий.

Как Python ищет модуль

Сначала интерпретатор проверяет встроенные модули, затем каталоги из списка sys.path. Для простого проекта в него входит каталог запускаемого файла. Поэтому соседний formatters.py находится автоматически.

Не называйте собственные файлы json.py, pathlib.py или именем другой используемой библиотеки. Такой файл может оказаться раньше настоящего модуля в пути поиска. Признак проблемы — сообщение об отсутствующем атрибуте у знакомой библиотеки или необычный путь в диагностике.

Увидеть файл, из которого загружен модуль, можно без изменения проекта. Выполните команду в каталоге server-report:

python -c "import formatters; print(formatters.__file__)"

Команда должна вывести путь к вашему formatters.py. Если показан другой файл, переименуйте конфликтующий модуль и удалите только созданные Python каталоги __pycache__, если старый импорт сохраняется после перезапуска.

Избегайте кольцевых импортов

Кольцевой импорт возникает, когда report.py импортирует formatters.py, а тот во время загрузки пытается импортировать report.py. Один из модулей остаётся частично созданным, поэтому нужное имя может ещё не существовать.

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

На этом шаге программа разделена по назначению, запускается из одного места и не выполняет работу при импорте. Следующий урок объясняет виртуальные окружения — отдельные каталоги для интерпретатора и внешних пакетов каждого проекта. Подробности синтаксиса подтверждает официальный раздел Python Modules.

Рекламное местоВаша компания здесьРазместить рекламу

Самопроверка

Проверьте, что материал усвоен

Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.

01Что Python называет модулем в простом проекте?
02Зачем обращаться к функции как formatters.format_status?
03Что предотвращает условие if __name__ == '__main__'?

Разбираем коротко

Частые вопросы

Чем модуль отличается от функции?

Функция объединяет одно действие, а модуль — определения и инструкции в отдельном файле Python. Один модуль обычно содержит несколько связанных функций, констант или классов.

Почему не стоит писать from module import *?

Так в текущий файл попадает неизвестный набор имён. Становится трудно понять их происхождение, а одинаковые имена могут незаметно заменить друг друга.

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

При первом импорте модуля в процессе Python. Поэтому на верхнем уровне оставляют определения и простую инициализацию, а запуск программы защищают условием __name__ == '__main__'.