История вопроса: Пакеты появились в Python для структурирования больших кодовых баз и для повторного использования кода. Они позволяют разбивать проект на логические модули и облегчать поддержку и импорт необходимого функционала.
Проблема: Некорректное понимание устройства пакетов приводит к ошибкам с импортом, конфликтам имён и ошибкам запуска скриптов. Важно знать разницу между пакетами и модулями, а также правила работы с относительными и абсолютными импортами.
Решение:
Пакет — это любая директория с файлом __init__.py (пустым или с инициализационным кодом). Пакеты могут содержать другие пакеты и модули. Пример структуры:
project/
├── mypackage/
│ ├── __init__.py
│ ├── mod1.py
│ └── subpackage/
│ ├── __init__.py
│ └── mod2.py
└── script.py
Для импорта используем относительный (from .subpackage import mod2) или абсолютный путь (from mypackage.subpackage import mod2). Абсолютные предпочтительнее для больших проектов.
Ключевые особенности:
__init__.pyДолжен ли обязательно присутствовать init.py в каждой папке, которую мы хотим сделать пакетом?
Да, для Python ниже 3.3; в современных версиях Python (3.3+) есть «неявные» namespace-пакеты, но для полной совместимости файл всё равно рекомендуется.
Что будет, если импортировать пакет, а не модуль?
Выполнится только код из __init__.py этого пакета.
В чём разница между импортом “from . import mod1” и “import mod1”?
from . import mod1 (относительный импорт) работает только внутри пакета, а абсолютный импорт ищет модуль в sys.path, что может привести к конфликтам имён.
__init__.pyНегативный кейс: Модули с одинаковыми именами в разных подпапках без использования абсолютных импортов. К одному модулю обращается не тот пакет, что планировалось. Плюсы:
Положительный кейс:
Явное задание абсолютных импортов, правильная структура папок и наличие __init__.py.
Плюсы: