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

Как понять, что директория с 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 — это пакет. Без неё (в старых версиях) — это просто папка.

Как понять, что директория с Python кодом является Python пакетом? | PrepBro