Python для дата-инженера — основы¶
Python — основной язык автоматизации в дата-инженерии. Ты пишешь на нём ETL-скрипты, работаешь с API, управляешь пайплайнами в Airflow и трансформируешь данные в pandas. В этой статье — минимум, который нужен DE-инженеру, чтобы уверенно читать и писать код.
Это не курс Python с нуля
Статья предполагает, что ты знаешь базовый синтаксис: переменные, циклы, функции. Здесь — фокус на инструментах и практиках, которые нужны именно дата-инженеру.
Зачем Python дата-инженеру¶
У Data Scientist, бэкенд-разработчика и дата-инженера — разные задачи на Python:
| Роль | Типичные задачи на Python |
|---|---|
| Data Scientist | Модели, эксперименты, Jupyter |
| Backend | HTTP-серверы, ORM, бизнес-логика |
| Data Engineer | ETL-скрипты, работа с API и БД, Airflow DAG, трансформации |
Дата-инженер чаще всего:
- забирает данные из REST API и складывает в хранилище;
- пишет DAG для Airflow (Python — основной язык DAG);
- читает/записывает файлы: CSV, JSON, Parquet;
- делает ad-hoc трансформации в pandas;
- автоматизирует инфраструктуру: миграции, бэкапы, мониторинг.
Виртуальные окружения¶
Каждый проект должен жить в изолированном окружении. Это защищает от конфликта зависимостей между проектами.
venv — встроенный модуль¶
# Создать окружение
python3 -m venv .venv
# Активировать
source .venv/bin/activate
# Установить зависимости
pip install pandas requests sqlalchemy
# Зафиксировать
pip freeze > requirements.txt
# Воспроизвести на другой машине
pip install -r requirements.txt
uv — быстрая замена pip¶
uv — менеджер пакетов от Astral (авторы ruff). Работает в 10–100 раз быстрее pip.
# Установить uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Создать проект
uv init my-etl-project
cd my-etl-project
# Добавить зависимости
uv add pandas requests sqlalchemy
# Запустить скрипт в окружении проекта
uv run python main.py
uv vs pip
uv автоматически создаёт .venv, управляет pyproject.toml и lock-файлом. Не нужно отдельно создавать окружение и фиксировать зависимости — всё из коробки.
poetry — для сложных проектов¶
Сравнение¶
| Критерий | venv + pip | uv | poetry |
|---|---|---|---|
| Скорость установки | Базовая | Очень быстрая | Средняя |
| Lock-файл | Нет (pip freeze) | Да (uv.lock) | Да (poetry.lock) |
| Управление Python | Нет | Да (uv python install) |
Нет |
| Кривая входа | Минимальная | Низкая | Средняя |
| Рекомендация | Обучение, скрипты | Новые проекты | Библиотеки с публикацией |
Не ставь пакеты глобально
pip install pandas без активного окружения ставит пакет в системный Python. Это ломает зависимости между проектами и может сломать системные утилиты.
Работа с файлами¶
CSV¶
import csv
from pathlib import Path
# Чтение
with Path("users.csv").open(encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], row["email"])
# Запись
rows = [
{"name": "Alice", "email": "alice@example.com"},
{"name": "Bob", "email": "bob@example.com"},
]
with Path("output.csv").open("w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["name", "email"])
writer.writeheader()
writer.writerows(rows)
Когда CSV не хватает
CSV не хранит типы данных и медленно читается на больших объёмах. Для аналитических задач используй Parquet.
JSON¶
import json
from pathlib import Path
# Чтение
data = json.loads(Path("config.json").read_text(encoding="utf-8"))
# Запись
Path("output.json").write_text(
json.dumps(data, ensure_ascii=False, indent=2),
encoding="utf-8",
)
Типичный паттерн DE — разобрать JSON-ответ API:
import json
raw = '{"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}'
payload = json.loads(raw)
for user in payload["users"]:
print(f"{user['id']}: {user['name']}")
Parquet¶
Parquet — колоночный формат. Занимает в 5–10 раз меньше места, чем CSV, и читается значительно быстрее.
import pyarrow as pa
import pyarrow.parquet as pq
# Создать таблицу
table = pa.table({
"user_id": [1, 2, 3],
"name": ["Alice", "Bob", "Carol"],
"score": [95.5, 87.3, 91.0],
})
# Записать в Parquet
pq.write_table(table, "users.parquet")
# Прочитать обратно
table = pq.read_table("users.parquet")
print(table.to_pandas())
pyarrow vs fastparquet
pyarrow — стандарт де-факто. fastparquet — легче, но менее совместим. Для DE-задач бери pyarrow.
Библиотеки DE-стека¶
pandas — трансформации данных¶
import pandas as pd
df = pd.read_csv("sales.csv")
result = (
df.groupby("region")["revenue"]
.sum()
.reset_index()
.sort_values("revenue", ascending=False)
)
print(result.head())
Подробнее — в статье pandas: трансформации данных.
requests — работа с API¶
import requests
response = requests.get(
"https://dummyjson.com/products",
params={"limit": 5},
timeout=10,
)
response.raise_for_status()
products = response.json()["products"]
for p in products:
print(f"{p['title']}: ${p['price']}")
Подробнее — в статье Работа с API.
SQLAlchemy — работа с базами данных¶
from sqlalchemy import create_engine, text
engine = create_engine("postgresql://user:pass@localhost:5432/mydb")
with engine.connect() as conn:
result = conn.execute(text("SELECT id, name FROM users LIMIT 5"))
for row in result:
print(row.id, row.name)
SQLAlchemy vs psycopg2
psycopg2 — низкоуровневый драйвер PostgreSQL. SQLAlchemy — ORM и toolkit, который работает поверх драйвера. Для DE-задач SQLAlchemy удобнее: pd.read_sql() принимает engine напрямую.
boto3 — AWS (S3, Redshift, Glue)¶
import boto3
s3 = boto3.client("s3")
# Загрузить файл в S3
s3.upload_file("data.parquet", "my-bucket", "raw/data.parquet")
# Скачать файл из S3
s3.download_file("my-bucket", "raw/data.parquet", "local_data.parquet")
Сводная таблица¶
| Библиотека | Задача | Установка |
|---|---|---|
| pandas | DataFrame, трансформации, read_csv/read_sql | pip install pandas |
| requests | HTTP-запросы к API | pip install requests |
| SQLAlchemy | Подключение к БД, ORM | pip install sqlalchemy |
| psycopg2 | Драйвер PostgreSQL | pip install psycopg2-binary |
| pyarrow | Parquet, Arrow-таблицы | pip install pyarrow |
| boto3 | AWS S3, Glue, Redshift | pip install boto3 |
| httpx | Async HTTP (замена requests) | pip install httpx |
Типизация и линтеры¶
Type hints¶
Python — динамический язык, но type hints помогают ловить ошибки до запуска:
def extract_users(api_url: str, limit: int = 100) -> list[dict]:
"""Забирает пользователей из API."""
import requests
response = requests.get(api_url, params={"limit": limit}, timeout=10)
response.raise_for_status()
return response.json()["users"]
Зачем типы в ETL
В ETL-скриптах данные проходят через много функций. Type hints — документация прямо в коде: сразу видно, что функция принимает и что возвращает.
ruff — линтер и форматтер¶
# Установить
pip install ruff
# Проверить код
ruff check .
# Исправить автоматически
ruff check --fix .
# Отформатировать
ruff format .
ruff заменяет flake8, isort, black и ещё десяток инструментов. Работает в 10–100 раз быстрее.
mypy — статическая проверка типов¶
Минимальная конфигурация для DE-проекта¶
[tool.ruff]
line-length = 120
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "UP"] # ошибки, import sort, upgrade
[tool.mypy]
python_version = "3.11"
warn_return_any = true
disallow_untyped_defs = true
Что запомнить¶
| Тема | Ключевая мысль |
|---|---|
| Окружения | Всегда используй виртуальное окружение. Для новых проектов — uv |
| Файлы | CSV для обмена, JSON для API, Parquet для аналитики |
| Библиотеки | pandas + requests + SQLAlchemy — базовый стек DE |
| Типизация | Type hints + ruff — минимум для читаемого кода |
Проверь себя¶
Источники¶
- The Python Tutorial — официальный tutorial, разделы по файлам и модулям
- uv — Getting Started — документация быстрого менеджера пакетов
- SQLAlchemy Unified Tutorial — работа с engine и connections
- pandas Getting Started — первые шаги с DataFrame
- pyarrow — Reading/Writing Parquet — документация по Parquet в Python
- ruff Documentation — линтер и форматтер