Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Пакет vs Модуль в Python: ключевые различия
В Python это два часто путаемых понятия, которые важны для организации кода в Data Engineering проектах.
Что такое модуль
Модуль — это один файл с расширением .py, содержащий Python код.
my_project/
├── utils.py # ← это модуль
├── data_loader.py # ← это модуль
└── main.py # ← это модуль
Пример модуля:
# utils.py — это модуль
def calculate_mean(data):
"""Вычисляет среднее значение"""
return sum(data) / len(data)
def calculate_std(data):
"""Вычисляет стандартное отклонение"""
mean = calculate_mean(data)
variance = sum((x - mean) ** 2 for x in data) / len(data)
return variance ** 0.5
CONSTANT = 42
Использование модуля:
# main.py
import utils # импортируем модуль
data = [1, 2, 3, 4, 5]
print(utils.calculate_mean(data)) # используем функцию из модуля
print(utils.calculate_std(data))
print(utils.CONSTANT) # используем константу
Что такое пакет
Пакет — это директория, содержащая модули и специальный файл __init__.py.
my_project/
├── utils/ # ← это пакет
│ ├── __init__.py # ← обязательно!
│ ├── statistics.py # ← модуль внутри пакета
│ ├── processing.py # ← модуль внутри пакета
│ └── data.py # ← модуль внутри пакета
├── pipeline/ # ← это тоже пакет
│ ├── __init__.py
│ ├── extract.py
│ ├── transform.py
│ └── load.py
└── main.py
Файл __init__.py — что там?
# utils/__init__.py
# Может быть пустым
# Или содержать инициализацию пакета
from .statistics import calculate_mean, calculate_std
from .data import load_data
from .processing import preprocess
# Экспортируем основные функции
__all__ = ['calculate_mean', 'calculate_std', 'load_data', 'preprocess']
print("Пакет utils инициализирован")
Ключевые различия
| Аспект | Модуль | Пакет |
|---|---|---|
| Что это | Файл .py | Директория с __init__.py |
| Содержит | Код, функции, классы | Другие модули и пакеты |
__init__.py | НЕ нужен | НУЖЕН (обязательно!) |
| Импорт | import module | import package.module или from package import module |
| Структура | Один файл | Иерархия файлов |
| Пример | utils.py | utils/__init__.py + utils/stats.py + utils/data.py |
Примеры импорта
Импорт из модуля:
# Вариант 1: импортируем весь модуль
import utils
utils.calculate_mean([1, 2, 3])
# Вариант 2: импортируем функцию
from utils import calculate_mean
calculate_mean([1, 2, 3])
# Вариант 3: импортируем с alias
from utils import calculate_mean as calc_avg
calc_avg([1, 2, 3])
Импорт из пакета:
# Вариант 1: из конкретного модуля в пакете
from utils.statistics import calculate_mean
calculate_mean([1, 2, 3])
# Вариант 2: напрямую из пакета (если __init__.py экспортирует)
from utils import calculate_mean # работает благодаря __init__.py
calculate_mean([1, 2, 3])
# Вариант 3: импортируем весь модуль из пакета
from utils import statistics
statistics.calculate_mean([1, 2, 3])
# Вариант 4: импортируем несколько функций
from utils import calculate_mean, load_data, preprocess
Практический пример: структура Data Engineering проекта
Хорошая структура:
data_pipeline/
├── config/ # Пакет для конфигурации
│ ├── __init__.py
│ ├── settings.py # Модуль
│ └── constants.py # Модуль
│
├── data_sources/ # Пакет для источников данных
│ ├── __init__.py
│ ├── api.py # Модуль для API
│ ├── database.py # Модуль для БД
│ └── csv_loader.py # Модуль для CSV
│
├── transformations/ # Пакет для трансформаций
│ ├── __init__.py
│ ├── cleaning.py # Модуль
│ ├── aggregations.py # Модуль
│ └── enrichment.py # Модуль
│
├── utils/ # Пакет для утилит
│ ├── __init__.py
│ ├── logging.py # Модуль
│ ├── date_helpers.py # Модуль
│ └── validators.py # Модуль
│
├── pipeline.py # Главный модуль (точка входа)
└── requirements.txt
Файл __init__.py для пакета:
# config/__init__.py
from .settings import DATABASE_URL, API_KEY, BATCH_SIZE
from .constants import TIMEOUT, MAX_RETRIES
__all__ = ['DATABASE_URL', 'API_KEY', 'BATCH_SIZE', 'TIMEOUT', 'MAX_RETRIES']
Использование в main коде:
# pipeline.py (точка входа)
from config import DATABASE_URL, BATCH_SIZE
from data_sources import load_from_api, load_from_database
from transformations import clean_data, aggregate_data
from utils import setup_logging, validate_data
def main():
setup_logging()
# Загружаем данные из разных источников
api_data = load_from_api() # из модуля api.py в пакете data_sources
db_data = load_from_database() # из модуля database.py в пакете data_sources
# Валидируем
validate_data(api_data)
validate_data(db_data)
# Трансформируем
cleaned = clean_data(api_data)
aggregated = aggregate_data(cleaned)
# Сохраняем в БД
with get_connection(DATABASE_URL) as conn:
save_to_database(aggregated, conn, batch_size=BATCH_SIZE)
if __name__ == '__main__':
main()
Пример реальной структуры: Spark ETL проект
spark_etl/
├── spark_etl/ # Пакет проекта
│ ├── __init__.py
│ │
│ ├── config/ # Пакет конфигурации
│ │ ├── __init__.py
│ │ ├── spark_config.py
│ │ └── env_config.py
│ │
│ ├── extractors/ # Пакет для Extract фазы
│ │ ├── __init__.py
│ │ ├── base.py # Базовый класс
│ │ ├── csv_extractor.py
│ │ ├── api_extractor.py
│ │ └── database_extractor.py
│ │
│ ├── transformers/ # Пакет для Transform фазы
│ │ ├── __init__.py
│ │ ├── data_cleaner.py
│ │ ├── aggregator.py
│ │ └── validator.py
│ │
│ ├── loaders/ # Пакет для Load фазы
│ │ ├── __init__.py
│ │ ├── parquet_loader.py
│ │ ├── delta_loader.py
│ │ └── database_loader.py
│ │
│ ├── pipeline/ # Пакет для оркестрации
│ │ ├── __init__.py
│ │ └── etl_pipeline.py
│ │
│ ├── utils/ # Пакет для утилит
│ │ ├── __init__.py
│ │ ├── logging.py
│ │ ├── spark_utils.py
│ │ └── date_utils.py
│ │
│ └── main.py # Модуль точки входа
│
├── tests/ # Тесты
│ ├── __init__.py
│ ├── test_extractors.py
│ ├── test_transformers.py
│ └── test_loaders.py
│
├── requirements.txt
└── setup.py
Использование такой структуры:
# spark_etl/main.py
from spark_etl.config import get_spark_config
from spark_etl.extractors import CSVExtractor, APIExtractor
from spark_etl.transformers import DataCleaner, Aggregator
from spark_etl.loaders import DeltaLoader
from spark_etl.pipeline import ETLPipeline
from spark_etl.utils import setup_logging, get_spark_session
def main():
setup_logging()
spark = get_spark_session(get_spark_config())
# Определяем компоненты
extractors = [
CSVExtractor(spark, 's3://raw/data.csv'),
APIExtractor(spark, 'https://api.example.com')
]
transformers = [
DataCleaner(),
Aggregator()
]
loaders = [DeltaLoader('s3://warehouse/output')]
# Запускаем pipeline
pipeline = ETLPipeline(extractors, transformers, loaders)
pipeline.execute()
if __name__ == '__main__':
main()
__init__.py: обязательный файл
Python 3.3+ поддерживает namespace packages, но для явной структуры нужен __init__.py:
# utils/__init__.py (пустой файл)
# Достаточно для того, чтобы Python считал это пакетом
# utils/__init__.py (с инициализацией)
from .statistics import calculate_mean
from .processing import preprocess
__version__ = '1.0.0'
__all__ = ['calculate_mean', 'preprocess']
print(f"Loading utils package v{__version__}")
Вывод
Модуль vs Пакет:
- Модуль = файл
.py(например,utils.py) - Пакет = директория с
__init__.py(например,utils/)
Когда использовать что:
- Модули: для простых, небольших наборов функций (< 500 строк)
- Пакеты: для организации кода в большие проекты с иерархией
Best Practice для Data Engineering:
- Разбивай код на пакеты по функциональности (extractors, transformers, loaders)
- Используй
__init__.pyдля экспорта публичного API - Избегай импорта из приватных модулей (
_internal.py) - Структурируй так, чтобы главный код был понятен с первого взгляда