← Назад к вопросам
Как понять, что директория с Python кодом является Python пакетом?
2.0 Middle🔥 121 комментариев
#Python Core#Soft Skills
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Python пакеты и модули
Директория становится Python пакетом благодаря специальному файлу.
1. init.py — главный маркер пакета
Директория является пакетом тогда и только тогда, когда в ней находится файл __init__.py:
my_project/
├── my_package/
│ ├── __init__.py # Это делает папку пакетом!
│ ├── module1.py
│ ├── module2.py
│ └── subpackage/
│ ├── __init__.py # Это тоже пакет
│ └── module3.py
└── main.py
2. Как Python определяет пакеты
# Это модуль (файл)
my_module.py # ✓ Можно импортировать
# Это директория, но НЕ пакет
my_folder/
├── file1.py
└── file2.py
# ✗ Невозможно импортировать: from my_folder import file1
# Это пакет
my_package/
├── __init__.py # ← Вот в чём разница
├── file1.py
└── file2.py
# ✓ Можно импортировать: from my_package import file1
3. init.py может быть пустым
# Пустой __init__.py — это ОК
# Файл может быть полностью пустым
my_package/
├── __init__.py # Пусто, но делает папку пакетом
├── models.py
├── views.py
└── utils.py
4. init.py как инициализатор пакета
# __init__.py может содержать код инициализации
# my_package/__init__.py
print("Пакет my_package инициализирован")
from .models import User, Post
from .views import index, detail
from .utils import helpers
__version__ = "1.0.0"
__author__ = "John Doe"
# Выполнится при первом импорте пакета
Этот код выполнится при импорте пакета:
import my_package # print: "Пакет my_package инициализирован"
# Теперь можно использовать
user = my_package.User()
5. Импорты в пакетах
# Структура
my_app/
├── __init__.py
├── models.py
├── views.py
└── helpers/
├── __init__.py
├── text_utils.py
└── date_utils.py
# my_app/models.py
class User:
pass
# my_app/views.py
from .models import User # Относительный импорт
from . import helpers # Импорт подпакета
def show_user():
user = User()
# ...
# my_app/helpers/__init__.py
from .text_utils import format_text
from .date_utils import format_date
# main.py (из другой папки)
from my_app import User # ✓ Работает
from my_app.models import User # ✓ Работает
from my_app.views import show_user # ✓ Работает
from my_app.helpers import format_text # ✓ Работает
6. Namespace пакеты (Python 3.3+)
В Python 3.3+ можно иметь пакет БЕЗ __init__.py (namespace package):
# Это тоже будет пакетом в Python 3.3+
my_namespace/
├── module1.py
├── module2.py
# Нет __init__.py, но пакет работает!
# Можно импортировать
from my_namespace import module1 # ✓ Работает
НО это не рекомендуется использовать для обычных пакетов. Namespace пакеты — для специальных случаев (например, плагины).
7. Как проверить, является ли директория пакетом
import os
import importlib.util
# Способ 1: Проверить наличие __init__.py
def is_package_old(directory):
return os.path.isfile(os.path.join(directory, '__init__.py'))
print(is_package_old('my_package')) # True если есть __init__.py
# Способ 2: Использовать importlib
import sys
import importlib.util
def is_package_modern(package_name):
spec = importlib.util.find_spec(package_name)
return spec is not None and spec.submodule_search_locations is not None
print(is_package_modern('my_package')) # True
# Способ 3: Проверить через sys.modules
import my_package
print(hasattr(my_package, '__path__')) # True для пакетов
print(hasattr(my_package, '__file__')) # True для всего
8. all в init.py
# my_package/__init__.py
from .models import User, Post
from .views import index, detail
from .utils import helpers
# Определить, что экспортируется при from my_package import *
__all__ = ['User', 'Post', 'index', 'detail']
# Теперь this работает:
from my_package import * # Импортирует только User, Post, index, detail
# helpers НЕ импортируется, т.к. не в __all__
9. Структура большого проекта
project/
├── setup.py # Конфигурация пакета
├── README.md
├── requirements.txt
├── my_app/ # Основной пакет
│ ├── __init__.py
│ ├── core/ # Подпакет
│ │ ├── __init__.py
│ │ ├── models.py
│ │ └── views.py
│ ├── api/ # Подпакет
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── serializers.py
│ └── utils/ # Подпакет
│ ├── __init__.py
│ ├── helpers.py
│ └── constants.py
└── tests/ # Пакет с тестами
├── __init__.py
├── test_models.py
├── test_views.py
└── conftest.py
10. Различие между модулем и пакетом
# Модуль — это файл
my_file.py
# Импорт: import my_file или from my_file import something
# Атрибут: __file__ есть, __path__ нет
# Пакет — это папка с __init__.py
my_package/
├── __init__.py
├── module1.py
└── module2.py
# Импорт: import my_package или from my_package import module1
# Атрибут: __file__ есть (на __init__.py), __path__ тоже есть
# Проверка
import my_file
print(hasattr(my_file, '__path__')) # False — это модуль
import my_package
print(hasattr(my_package, '__path__')) # True — это пакет
print(my_package.__path__) # ['/path/to/my_package']
11. Типичная ошибка
# ✗ Ошибка: DirectoryError
my_folder/
├── models.py
└── views.py
from my_folder import models # ModuleNotFoundError!
# Исправление: добавить __init__.py
my_folder/
├── __init__.py # ← Добавить этот файл
├── models.py
└── views.py
from my_folder import models # ✓ Теперь работает
Ключевые моменты
- init.py — обязательный файл для пакета (в Python < 3.3 или для явности)
- Namespace пакеты — без
__init__.pyработают в Python 3.3+, но не рекомендуются - path — атрибут, который есть только в пакетах
- all — контролирует экспорт при
import * - Модуль — файл, пакет — папка с
__init__.py - Инициализация — код в
__init__.pyвыполняется при импорте пакета
Просто помни: если есть __init__.py — это пакет. Без неё (в старых версиях) — это просто папка.