python-programming について
python-programmingは、Pythonによるデータエンジニアリングの学習・参照スキルです。型付け、ジェネレーター、非同期I/O、テスト、運用手法を扱い、本番向けのパイプラインやデータ集約型アプリケーションを支援します。
主な機能
- 01型安全なデータ構造
- 02大規模データ向けジェネレーター
- 03非同期I/Oプログラミング
- 04エラー処理とログ記録
- 05テストと性能改善の手法
活用シーン
- 01スケーラブルなETLパイプラインの構築
- 02大容量ファイルの分割処理
- 03I/O負荷の高いタスクの並行処理
- 04本番環境のPythonコードのテストと調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ pluginagentmarketplace/ custom-plugin-data-engineer --skill python-programmingインストール後、Claude Code で/python-programmingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/config.yamlschema.jsonreferences/GUIDE.mdPATTERNS.mdscripts/validate.py詳細
データエンジニアリングのためのPythonプログラミング
スケーラブルなデータパイプライン、ETLシステム、データ集約型アプリケーションを構築するための、本番環境向けPython開発です。
クイックスタート
# Modern Python 3.12+ data engineering setup
from dataclasses import dataclass
from typing import Generator
from collections.abc import Iterator
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
@dataclass
class DataRecord:
"""Type-safe data container with validation."""
id: int
value: float
category: str
def __post_init__(self):
if self.value < 0:
raise ValueError(f"Value must be non-negative, got {self.value}")
def process_records(records: Iterator[dict]) -> Generator[DataRecord, None, None]:
"""Memory-efficient generator for processing large datasets."""
for idx, record in enumerate(records):
try:
yield DataRecord(
id=record['id'],
value=float(record['value']),
category=record.get('category', 'unknown')
)
except (KeyError, ValueError) as e:
logger.warning(f"Skipping invalid record {idx}: {e}")
continue
# Usage
if __name__ == "__main__":
sample_data = [{"id": 1, "value": "100.5", "category": "A"}]
for record in process_records(iter(sample_data)):
logger.info(f"Processed: {record}")
基本概念
1. 型安全なデータ構造(2024~2025年の標準)
from typing import TypedDict, NotRequired, Literal
from dataclasses import dataclass, field
from datetime import datetime
# TypedDict for JSON-like structures
class PipelineConfig(TypedDict):
source: str
destination: str
batch_size: int
retry_count: NotRequired[int]
mode: Literal["batch", "streaming"]
# Dataclass for domain objects
@dataclass(frozen=True, slots=True)
class ETLJob:
"""Immutable, memory-efficient job definition."""
job_id: str
created_at: datetime = field(default_factory=datetime.utcnow)
config: dict = field(default_factory=dict)
def to_dict(self) -> dict:
return {"job_id": self.job_id, "created_at": self.created_at.isoformat()}
2. 大規模データ向けジェネレーターパターン
from typing import Generator, Iterable
import csv
from pathlib import Path
def read_csv_chunks(
file_path: Path,
chunk_size: int = 10000
) -> Generator[list[dict], None, None]:
"""
Memory-efficient CSV reader using generators.
Processes files of any size without loading into memory.
"""
with open(file_path, 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
chunk = []
for row in reader:
chunk.append(row)
if len(chunk) >= chunk_size:
yield chunk
chunk = []
if chunk: # Don't forget the last chunk
yield chunk
def transform_pipeline(
records: Iterable[dict],
transformers: list[callable]
) -> Generator[dict, None, None]:
"""Composable transformation pipeline."""
for record in records:
result = record
for transform in transformers:
result = transform(result)
if result is None:
break
if result is not None:
yield result
3. I/Oバウンドなタスク向けの非同期プログラミング
import asyncio
import aiohttp
from typing import AsyncGenerator
import logging
logger = logging.getLogger(__name__)
async def fetch_with_retry(
session: aiohttp.ClientSession,
url: str,
max_retries: int = 3,
backoff_factor: float = 2.0
) -> dict | None:
"""
Fetch URL with exponential backoff retry logic.
Production pattern for API data ingestion.
"""
for attempt in range(max_retries):
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=30)) as resp:
resp.raise_for_status()
return await resp.json()
except aiohttp.ClientError as e:
wait_time = backoff_factor ** attempt
logger.warning(f"Attempt {attempt+1} failed for {url}: {e}. Retrying in {wait_time}s")
await asyncio.sleep(wait_time)
logger.error(f"All retries exhausted for {url}")
return None
async def fetch_all_pages(
base_url: str,
page_count: int,
concurrency_limit: int = 10
) -> AsyncGenerator[dict, None]:
"""Concurrent API fetching with rate limiting."""
semaphore = asyncio.Semaphore(concurrency_limit)
async def bounded_fetch(session: aiohttp.ClientSession, url: str):
async with semaphore:
return await fetch_with_retry(session, url)
async with aiohttp.ClientSession() as session:
tasks = [bounded_fetch(session, f"{base_url}?page={i}") for i in range(page_count)]
for result in asyncio.as_completed(tasks):
data = await result
if data:
yield data
4. エラーハンドリングと可観測性
import functools
import time
import logging
from typing import TypeVar, Callable, ParamSpec
P = ParamSpec('P')
R = TypeVar('R')
def with_retry(
max_attempts: int = 3,
exceptions: tuple = (Exception,),
backoff_factor: float = 2.0
) -> Callable[[Callable[P, R]], Callable[P, R]]:
"""
Decorator for automatic retry with exponential backoff.
Use for flaky operations (network, database connections).
"""
def decorator(func: Callable[P, R]) -> Callable[P, R]:
@functools.wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
last_exception = None
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except exceptions as e:
last_exception = e
wait_time = backoff_factor ** attempt
logging.warning(
f"{func.__name__} attempt {attempt+1} failed: {e}. "
f"Retrying in {wait_time}s"
)
time.sleep(wait_time)
raise last_exception
return wrapper
return decorator
def log_execution_time(func: Callable[P, R]) -> Callable[P, R]:
"""Decorator for performance monitoring."""
@functools.wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
start = time.perf_counter()
try:
result = func(*args, **kwargs)
duration = time.perf_counter() - start
logging.info(f"{func.__name__} completed in {duration:.3f}s")
return result
except Exception as e:
duration = time.perf_counter() - start
logging.error(f"{func.__name__} failed after {duration:.3f}s: {e}")
raise
return wrapper
ツールとテクノロジー
| ツール | 用途 | バージョン(2025年) |
|---|---|---|
| Python | コア言語 | 3.12+ |
| uv | パッケージマネージャー(pipを置き換え) | 0.4+ |
| Ruff | リンター+フォーマッター(Black、flake8を置き換え) | 0.5+ |
| mypy | 静的型チェック | 1.11+ |
| pytest | テストフレームワーク | 8.0+ |
| pydantic | データ検証 | 2.5+ |
| polars | DataFrame操作(pandasより高速) | 0.20+ |
| httpx | 最新のHTTPクライアント | 0.27+ |
学習ロードマップ
フェーズ1:基礎(1~3週目)
Week 1: Core syntax, data types, control flow
Week 2: Functions, modules, file I/O
Week 3: OOP (classes, inheritance, composition)
フェーズ2:中級(4~6週目)
Week 4: Generators, iterators, decorators
Week 5: Type hints, dataclasses, protocols
Week 6: Error handling, logging, testing basics
フェーズ3:上級(7~9週目)
Week 7: Async/await, concurrent programming
Week 8: Memory optimization, profiling
Week 9: Package structure, dependency management
フェーズ4:本番環境の習熟(10~12週目)
Week 10: CI/CD integration, linting, formatting
Week 11: Performance optimization patterns
Week 12: Production deployment patterns
本番環境向けパターン
設定管理
from pydantic_settings import BaseSettings
from functools import lru_cache
class Settings(BaseSettings):
"""Type-safe configuration with environment variable support."""
database_url: str
api_key: str
batch_size: int = 1000
debug: bool = False
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
@lru_cache
def get_settings() -> Settings:
"""Cached settings singleton."""
return Settings()
コネクションプーリング
from contextlib import contextmanager
from typing import Generator
import psycopg2
from psycopg2 import pool
class DatabasePool:
"""Thread-safe connection pool for PostgreSQL."""
def __init__(self, dsn: str, min_conn: int = 2, max_conn: int = 10):
self._pool = pool.ThreadedConnectionPool(min_conn, max_conn, dsn)
@contextmanager
def get_connection(self) -> Generator:
conn = self._pool.getconn()
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
finally:
self._pool.putconn(conn)
def close(self):
self._pool.closeall()
トラブルシューティングガイド
よくある障害パターン
| 問題 | 症状 | 根本原因 | 対処法 |
|---|---|---|---|
| メモリエラー | MemoryError、プロセスが強制終了される | データセット全体をメモリに読み込んでいる | ジェネレーター、チャンク処理を使用する |
| インポートエラー | ModuleNotFoundError | 仮想環境が有効化されていない、依存パッケージが不足している | uv pip installを実行し、sys.pathを確認する |
| 型エラー | TypeError: unhashable type | 変更可能なオブジェクトを辞書のキーに使用している | タプルに変換するか、データクラスを使用する |
| 非同期デッドロック | プログラムが停止する | 非同期コード内でブロッキング呼び出しを使用している | ブロッキング処理にはasyncio.to_thread()を使用する |
| GILのボトルネック | CPUバウンドの並列処理が遅い | PythonのGILがスレッドを制限している | multiprocessingまたはProcessPoolExecutorを使用する |
デバッグチェックリスト
# 1. Check Python version
python --version # Should be 3.12+
# 2. Verify virtual environment
which python # Should point to venv
# 3. Check installed packages
uv pip list | grep <package>
# 4. Run with verbose logging
python -m mymodule -v 2>&1 | tee debug.log
# 5. Profile memory usage
python -m memory_profiler script.py
# 6. Profile CPU
python -m cProfile -s cumtime script.py
ログの読み解き方
# Structured logging for easier debugging
import structlog
logger = structlog.get_logger()
def process_batch(batch_id: str, records: list):
logger.info("batch_started", batch_id=batch_id, record_count=len(records))
try:
# processing...
logger.info("batch_completed", batch_id=batch_id, success=True)
except Exception as e:
logger.error("batch_failed", batch_id=batch_id, error=str(e), exc_info=True)
raise
単体テストのテンプレート
import pytest
from unittest.mock import Mock, patch
from your_module import process_records, DataRecord
class TestProcessRecords:
"""Unit tests following AAA pattern (Arrange-Act-Assert)."""
def test_valid_records_processed(self):
# Arrange
input_data = [{"id": 1, "value": "10.5", "category": "A"}]
# Act
result = list(process_records(iter(input_data)))
# Assert
assert len(result) == 1
assert result[0].id == 1
assert result[0].value == 10.5
def test_invalid_records_skipped(self):
# Arrange
input_data = [{"id": 1}] # Missing 'value'
# Act
result = list(process_records(iter(input_data)))
# Assert
assert len(result) == 0
def test_negative_value_raises_error(self):
# Arrange & Act & Assert
with pytest.raises(ValueError, match="non-negative"):
DataRecord(id=1, value=-5.0, category="A")
@patch('your_module.external_api_call')
def test_with_mocked_dependency(self, mock_api):
# Arrange
mock_api.return_value = {"status": "ok"}
# Act
result = function_using_api()
# Assert
mock_api.assert_called_once()
assert result["status"] == "ok"
ベストプラクティス
コードスタイル(2025年の標準)
# ✅ DO: Use type hints everywhere
def calculate_metrics(data: list[float]) -> dict[str, float]: ...
# ✅ DO: Prefer composition over inheritance
@dataclass
class Pipeline:
reader: DataReader
transformer: Transformer
writer: DataWriter
# ✅ DO: Use context managers for resources
with open_connection() as conn:
process(conn)
# ❌ DON'T: Use bare except
try: ...
except: pass # Never do this
# ❌ DON'T: Mutate function arguments
def process(items: list) -> list:
items.append("new") # Avoid this
return items.copy() # Return new list instead
パフォーマンスのヒント
# ✅ Use generators for large data
def process_large_file(path):
with open(path) as f:
for line in f: # Memory efficient
yield transform(line)
# ✅ Use set/dict for O(1) lookups
valid_ids = set(load_valid_ids()) # Not list
if item_id in valid_ids: ...
# ✅ Use local variables in hot loops
def hot_loop(items):
local_func = expensive_lookup # Cache reference
for item in items:
local_func(item)
リソース
公式ドキュメント
本番環境向けの参考資料
コミュニティ
次に学ぶスキル
Pythonプログラミングを習得した後は、次に進みましょう。
- →
sql-databases- リレーショナルデータのクエリと管理 - →
etl-tools- Airflowを使ったデータパイプラインの構築 - →
big-data- Sparkと分散システムによるスケーリング - →
machine-learning- scikit-learnによるMLの活用
スキル認定チェックリスト:
- mypyによる検証を使って型安全なPythonを書ける
- 大規模データ処理向けのジェネレーターを実装できる
- 並行I/Oにasync/awaitを使用できる
- pytestを使って包括的な単体テストを書ける
- Pythonのパフォーマンスをプロファイルして最適化できる
コメント
Markdown 対応