Импорт модулей и пакетов в Python: понятное руководство с примерами
Поисковый запрос: «Импорт модулей в Python» — частый гость у начинающих. Ниже вы найдёте пошаговое объяснение, как работает механизм импорта, чем модуль отличается от пакета, как устроен поиск по sys.path, что такое абсолютные и относительные импорты, и как организовать проект, чтобы не ловить ModuleNotFoundError.
Модуль и пакет: в чём разница
Модуль — это обычный .py-файл. Пакет — это папка с файлами Python, которую интерпретатор воспринимает как единое пространство имён. В современных версиях Python пакет может быть:
__init__.py__init__.py (удобно для распределённых пакетов)Как работает import в Python
sys.modules — повторный импорт быстрый и не выполняет модуль заново.sys.path (текущая папка, путь скрипта, установленные пакеты, стандартная библиотека и др.).# demo_module.py
print("Верхнеуровневый код исполнился при импорте")
VALUE = 42
# main.py
import demo_module
print(demo_module.VALUE)
Запуск python main.py выведет сообщение из demo_module один раз, даже если вы импортируете его в нескольких местах.
Абсолютные и относительные импорты
Абсолютный импорт указывает путь от корня пакета: from app.utils import text. Относительный импорт опирается на текущее положение модуля и использует точки: from .utils import text или from ..common import constants.
# Структура проекта
app/
├─ __init__.py
├─ utils/
│ ├─ __init__.py
│ └─ text.py
└─ services/
├─ __init__.py
└─ processor.py
# app/utils/text.py
def slugify(s: str) -> str:
return s.lower().replace(" ", "-")
# app/services/processor.py
from ..utils.text import slugify # относительный импорт
def process(title: str) -> str:
return slugify(title).strip("-")
# main.py (на уровень выше app)
from app.services.processor import process # абсолютный импорт
print(process(" Hello World "))
Совет: внутри пакета используйте относительные импорты для локальных зависимостей; для кода вне пакета — абсолютные. Это упрощает переносимость и чтение.
PYTHONPATH и sys.path: где Python ищет модули
Если при запуске вы получаете ModuleNotFoundError, скорее всего каталог проекта не в sys.path. Временное решение — добавить путь в переменную окружения PYTHONPATH или модифицировать sys.path в рантайме (на свой страх и риск).
# Временно для одной сессии Linux/macOS
export PYTHONPATH=$(pwd)
python main.py
# Временно для одной сессии Windows (PowerShell)
$env:PYTHONPATH=Get-Location
python main.py
# В коде (не рекомендуется как постоянная практика)
import sys, pathlib
sys.path.append(str(pathlib.Path(__file__).resolve().parent))
Правильнее — запускать скрипт из корня проекта или оформлять исполняемые точки входа через пакетный менеджер.
Роль __init__.py и __all__
__init__.py делает папку обычным пакетом и может выполнять код инициализации. Через __all__ можно контролировать экспорт при from package import * (звёздочный импорт лучше избегать, но знать полезно).
# app/utils/__init__.py
from .text import slugify
__all__ = ["slugify"]
# Теперь:
from app.utils import *
print(slugify("Hello Python"))
Типичные ошибки и как их исправить
-m.# Правильно запускать пакетный модуль так:
python -m app.services.processor
# Внутри модуля защищайте исполняемый код:
if __name__ == "__main__":
print(process("Run as module"))
Циклические импорты: как распознать и лечить
Цикл возникает, когда a.py импортирует b.py, а b.py — обратно a.py. Симптомы: атрибуты None, частично инициализированные модули, странные ошибки при импорте.
# a.py
def use_b(x):
from b import transform # локальный импорт, избегает цикла на уровне модуля
return transform(x)
# b.py
def transform(x):
return x * 2
Импорт эффективно: практические советы
import numpy as np — короче и принят в сообществе для больших библиотек.from pathlib import Path — ускоряет доступ и повышает читаемость.from x import * ухудшает читаемость и может ломать автодополнение IDE.Рекомендуемая структура проекта
project/
├─ pyproject.toml
├─ README.md
├─ src/
│ └─ app/
│ ├─ __init__.py
│ ├─ utils/
│ │ ├─ __init__.py
│ │ └─ text.py
│ └─ services/
│ ├─ __init__.py
│ └─ processor.py
└─ tests/
└─ test_processor.py
# Настраивайте IDE/тесты так, чтобы корень src попадал в sys.path,
# либо запускайте из корня:
python -m app.services.processor # если cwd = src
Быстрый чек‑лист при ошибках импорта
pwd и IDE Run Configuration.random.py)__init__.py? Для обычных пакетов — да.Где прокачаться дальше
Хотите уверенно разбираться в структуре проектов, импортах и лучших практиках? Посмотрите программу курса — он ведёт от основ к продвинутым темам:
Пройти курс «Программирование на Python с Нуля до Гуру» и прокачать импорты на практике
Итоги
Импорт модулей в Python — не магия, а понятный механизм: модуль выполняется один раз, кэшируется в sys.modules, а поиск идёт по sys.path. Грамотная структура проекта, осознанный выбор между абсолютными и относительными импортами, минимизация побочных эффектов и внимательность к циклическим зависимостям избавят вас от большинства ошибок на ранних этапах разработки.



