Skip to content
cccskills
FreePublished on GitHub

python-patterns

Pythonらしいイディオム、PEP 8標準、型ヒント、堅牢で効率的かつ保守性の高いPythonアプリケーションを構築するためのベストプラクティス。

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md17.6 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Python開発パターン

Pythonらしいパターンとベストプラクティスにより、堅牢で効率的かつ保守性の高いアプリケーションを構築します。

アクティベーション条件

  • 新しいPythonコードを書くとき
  • Pythonコードをレビューするとき
  • 既存のPythonコードをリファクタリングするとき
  • Pythonパッケージ/モジュールを設計するとき

基本原則

1. 可読性が重要

Pythonは可読性を優先します。コードは明白で理解しやすいものであるべきです。

# Good: 明確で読みやすい
def get_active_users(users: list[User]) -> list[User]:
    """Return only active users from the provided list."""
    return [user for user in users if user.is_active]


# Bad: 賢いが分かりにくい
def get_active_users(u):
    return [x for x in u if x.a]

2. 暗黙より明示

マジックを避け、コードが何をするか明確にしましょう。

# Good: 明示的な設定
import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

# Bad: 隠された副作用
import some_module
some_module.setup()  # What does this do?

3. EAFP - 許可を求めるより許しを請う方が簡単

Pythonは条件チェックよりも例外処理を好みます。

# Good: EAFPスタイル
def get_value(dictionary: dict, key: str) -> Any:
    try:
        return dictionary[key]
    except KeyError:
        return default_value

# Bad: LBYL(飛ぶ前に見る)スタイル
def get_value(dictionary: dict, key: str) -> Any:
    if key in dictionary:
        return dictionary[key]
    else:
        return default_value

型ヒント

基本的な型アノテーション

from typing import Optional, List, Dict, Any

def process_user(
    user_id: str,
    data: Dict[str, Any],
    active: bool = True
) -> Optional[User]:
    """Process a user and return the updated User or None."""
    if not active:
        return None
    return User(user_id, data)

モダンな型ヒント(Python 3.9以降)

# Python 3.9+ - 組み込み型を使用
def process_items(items: list[str]) -> dict[str, int]:
    return {item: len(item) for item in items}

# Python 3.8以前 - typingモジュールを使用
from typing import List, Dict

def process_items(items: List[str]) -> Dict[str, int]:
    return {item: len(item) for item in items}

型エイリアスとTypeVar

from typing import TypeVar, Union

# 複雑な型の型エイリアス
JSON = Union[dict[str, Any], list[Any], str, int, float, bool, None]

def parse_json(data: str) -> JSON:
    return json.loads(data)

# ジェネリック型
T = TypeVar('T')

def first(items: list[T]) -> T | None:
    """Return the first item or None if list is empty."""
    return items[0] if items else None

プロトコルベースのダックタイピング

from typing import Protocol

class Renderable(Protocol):
    def render(self) -> str:
        """Render the object to a string."""

def render_all(items: list[Renderable]) -> str:
    """Render all items that implement the Renderable protocol."""
    return "\n".join(item.render() for item in items)

エラーハンドリングパターン

特定の例外処理

# Good: 特定の例外をキャッチ
def load_config(path: str) -> Config:
    try:
        with open(path) as f:
            return Config.from_json(f.read())
    except FileNotFoundError as e:
        raise ConfigError(f"Config file not found: {path}") from e
    except json.JSONDecodeError as e:
        raise ConfigError(f"Invalid JSON in config: {path}") from e

# Bad: ベアexcept
def load_config(path: str) -> Config:
    try:
        with open(path) as f:
            return Config.from_json(f.read())
    except:
        return None  # Silent failure!

例外チェーン

def process_data(data: str) -> Result:
    try:
        parsed = json.loads(data)
    except json.JSONDecodeError as e:
        # トレースバックを保持するために例外をチェーン
        raise ValueError(f"Failed to parse data: {data}") from e

カスタム例外階層

class AppError(Exception):
    """Base exception for all application errors."""
    pass

class ValidationError(AppError):
    """Raised when input validation fails."""
    pass

class NotFoundError(AppError):
    """Raised when a requested resource is not found."""
    pass

# 使用例
def get_user(user_id: str) -> User:
    user = db.find_user(user_id)
    if not user:
        raise NotFoundError(f"User not found: {user_id}")
    return user

コンテキストマネージャー

リソース管理

# Good: コンテキストマネージャーの使用
def process_file(path: str) -> str:
    with open(path, 'r') as f:
        return f.read()

# Bad: 手動のリソース管理
def process_file(path: str) -> str:
    f = open(path, 'r')
    try:
        return f.read()
    finally:
        f.close()

カスタムコンテキストマネージャー

from contextlib import contextmanager

@contextmanager
def timer(name: str):
    """Context manager to time a block of code."""
    start = time.perf_counter()
    yield
    elapsed = time.perf_counter() - start
    print(f"{name} took {elapsed:.4f} seconds")

# 使用例
with timer("data processing"):
    process_large_dataset()

コンテキストマネージャークラス

class DatabaseTransaction:
    def __init__(self, connection):
        self.connection = connection

    def __enter__(self):
        self.connection.begin_transaction()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is None:
            self.connection.commit()
        else:
            self.connection.rollback()
        return False  # Don't suppress exceptions

# 使用例
with DatabaseTransaction(conn):
    user = conn.create_user(user_data)
    conn.create_profile(user.id, profile_data)

内包表記とジェネレーター

リスト内包表記

# Good: シンプルな変換にはリスト内包表記
names = [user.name for user in users if user.is_active]

# Bad: 手動ループ
names = []
for user in users:
    if user.is_active:
        names.append(user.name)

# 複雑な内包表記は展開すべき
# Bad: 複雑すぎる
result = [x * 2 for x in items if x > 0 if x % 2 == 0]

# Good: ジェネレーター関数を使用
def filter_and_transform(items: Iterable[int]) -> list[int]:
    result = []
    for x in items:
        if x > 0 and x % 2 == 0:
            result.append(x * 2)
    return result

ジェネレーター式

# Good: 遅延評価のジェネレーター
total = sum(x * x for x in range(1_000_000))

# Bad: 大きな中間リストを生成
total = sum([x * x for x in range(1_000_000)])

ジェネレーター関数

def read_large_file(path: str) -> Iterator[str]:
    """Read a large file line by line."""
    with open(path) as f:
        for line in f:
            yield line.strip()

# 使用例
for line in read_large_file("huge.txt"):
    process(line)

データクラスと名前付きタプル

データクラス

from dataclasses import dataclass, field
from datetime import datetime

@dataclass
class User:
    """User entity with automatic __init__, __repr__, and __eq__."""
    id: str
    name: str
    email: str
    created_at: datetime = field(default_factory=datetime.now)
    is_active: bool = True

# 使用例
user = User(
    id="123",
    name="Alice",
    email="alice@example.com"
)

バリデーション付きデータクラス

@dataclass
class User:
    email: str
    age: int

    def __post_init__(self):
        # メール形式のバリデーション
        if "@" not in self.email:
            raise ValueError(f"Invalid email: {self.email}")
        # 年齢範囲のバリデーション
        if self.age < 0 or self.age > 150:
            raise ValueError(f"Invalid age: {self.age}")

名前付きタプル

from typing import NamedTuple

class Point(NamedTuple):
    """Immutable 2D point."""
    x: float
    y: float

    def distance(self, other: 'Point') -> float:
        return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5

# 使用例
p1 = Point(0, 0)
p2 = Point(3, 4)
print(p1.distance(p2))  # 5.0

デコレーター

関数デコレーター

import functools
import time

def timer(func: Callable) -> Callable:
    """Decorator to time function execution."""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"{func.__name__} took {elapsed:.4f}s")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)

# slow_function() prints: slow_function took 1.0012s

パラメータ付きデコレーター

def repeat(times: int):
    """Decorator to repeat a function multiple times."""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            results = []
            for _ in range(times):
                results.append(func(*args, **kwargs))
            return results
        return wrapper
    return decorator

@repeat(times=3)
def greet(name: str) -> str:
    return f"Hello, {name}!"

# greet("Alice") returns ["Hello, Alice!", "Hello, Alice!", "Hello, Alice!"]

クラスベースデコレーター

class CountCalls:
    """Decorator that counts how many times a function is called."""
    def __init__(self, func: Callable):
        functools.update_wrapper(self, func)
        self.func = func
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} has been called {self.count} times")
        return self.func(*args, **kwargs)

@CountCalls
def process():
    pass

# Each call to process() prints the call count

並行処理パターン

I/Oバウンドタスク向けスレッディング

import concurrent.futures
import threading

def fetch_url(url: str) -> str:
    """Fetch a URL (I/O-bound operation)."""
    import urllib.request
    with urllib.request.urlopen(url) as response:
        return response.read().decode()

def fetch_all_urls(urls: list[str]) -> dict[str, str]:
    """Fetch multiple URLs concurrently using threads."""
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        future_to_url = {executor.submit(fetch_url, url): url for url in urls}
        results = {}
        for future in concurrent.futures.as_completed(future_to_url):
            url = future_to_url[future]
            try:
                results[url] = future.result()
            except Exception as e:
                results[url] = f"Error: {e}"
    return results

CPUバウンドタスク向けマルチプロセシング

def process_data(data: list[int]) -> int:
    """CPU-intensive computation."""
    return sum(x ** 2 for x in data)

def process_all(datasets: list[list[int]]) -> list[int]:
    """Process multiple datasets using multiple processes."""
    with concurrent.futures.ProcessPoolExecutor() as executor:
        results = list(executor.map(process_data, datasets))
    return results

並行I/O向けAsync/Await

import asyncio

async def fetch_async(url: str) -> str:
    """Fetch a URL asynchronously."""
    import aiohttp
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def fetch_all(urls: list[str]) -> dict[str, str]:
    """Fetch multiple URLs concurrently."""
    tasks = [fetch_async(url) for url in urls]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    return dict(zip(urls, results))

パッケージ構成

標準的なプロジェクトレイアウト

myproject/
├── src/
│   └── mypackage/
│       ├── __init__.py
│       ├── main.py
│       ├── api/
│       │   ├── __init__.py
│       │   └── routes.py
│       ├── models/
│       │   ├── __init__.py
│       │   └── user.py
│       └── utils/
│           ├── __init__.py
│           └── helpers.py
├── tests/
│   ├── __init__.py
│   ├── conftest.py
│   ├── test_api.py
│   └── test_models.py
├── pyproject.toml
├── README.md
└── .gitignore

インポート規約

# Good: インポート順序 - 標準ライブラリ、サードパーティ、ローカル
import os
import sys
from pathlib import Path

import requests
from fastapi import FastAPI

from mypackage.models import User
from mypackage.utils import format_name

# Good: isortで自動インポートソート
# pip install isort

パッケージエクスポート用__init__.py

# mypackage/__init__.py
"""mypackage - A sample Python package."""

__version__ = "1.0.0"

# パッケージレベルでメインのクラス/関数をエクスポート
from mypackage.models import User, Post
from mypackage.utils import format_name

__all__ = ["User", "Post", "format_name"]

メモリとパフォーマンス

メモリ効率のための__slots__の使用

# Bad: 通常のクラスは__dict__を使用(メモリ消費が多い)
class Point:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

# Good: __slots__でメモリ使用量を削減
class Point:
    __slots__ = ['x', 'y']

    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

大量データ向けジェネレーター

# Bad: メモリにリスト全体を返す
def read_lines(path: str) -> list[str]:
    with open(path) as f:
        return [line.strip() for line in f]

# Good: 一度に1行ずつyield
def read_lines(path: str) -> Iterator[str]:
    with open(path) as f:
        for line in f:
            yield line.strip()

ループ内の文字列連結を避ける

# Bad: 文字列のイミュータビリティによりO(n²)
result = ""
for item in items:
    result += str(item)

# Good: joinを使用してO(n)
result = "".join(str(item) for item in items)

# Good: StringIOで構築
from io import StringIO

buffer = StringIO()
for item in items:
    buffer.write(str(item))
result = buffer.getvalue()

Pythonツール統合

必須コマンド

# コードフォーマット
black .
isort .

# リンティング
ruff check .
pylint mypackage/

# 型チェック
mypy .

# テスト
pytest --cov=mypackage --cov-report=html

# セキュリティスキャン
bandit -r .

# 依存関係管理
pip-audit
safety check

pyproject.toml設定

[project]
name = "mypackage"
version = "1.0.0"
requires-python = ">=3.9"
dependencies = [
    "requests>=2.31.0",
    "pydantic>=2.0.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.4.0",
    "pytest-cov>=4.1.0",
    "black>=23.0.0",
    "ruff>=0.1.0",
    "mypy>=1.5.0",
]

[tool.black]
line-length = 88
target-version = ['py39']

[tool.ruff]
line-length = 88
select = ["E", "F", "I", "N", "W"]

[tool.mypy]
python_version = "3.9"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--cov=mypackage --cov-report=term-missing"

クイックリファレンス: Pythonイディオム

イディオム説明
EAFP許可を求めるより許しを請う方が簡単
コンテキストマネージャーリソース管理に with を使用
リスト内包表記シンプルな変換に使用
ジェネレーター遅延評価と大規模データセットに使用
型ヒント関数シグネチャにアノテーション
データクラス自動生成メソッド付きデータコンテナに使用
__slots__メモリ最適化に使用
f-strings文字列フォーマットに使用(Python 3.6以降)
pathlib.Pathパス操作に使用(Python 3.4以降)
enumerateループ内のインデックスと要素のペアに使用

避けるべきアンチパターン

# Bad: ミュータブルなデフォルト引数
def append_to(item, items=[]):
    items.append(item)
    return items

# Good: Noneを使用して新しいリストを作成
def append_to(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

# Bad: type()で型チェック
if type(obj) == list:
    process(obj)

# Good: isinstanceを使用
if isinstance(obj, list):
    process(obj)

# Bad: ==でNoneと比較
if value == None:
    process()

# Good: isを使用
if value is None:
    process()

# Bad: from module import *
from os.path import *

# Good: 明示的なインポート
from os.path import join, exists

# Bad: ベアexcept
try:
    risky_operation()
except:
    pass

# Good: 特定の例外
try:
    risky_operation()
except SpecificError as e:
    logger.error(f"Operation failed: {e}")

覚えておくこと: Pythonコードは読みやすく、明示的で、最小驚きの原則に従うべきです。迷ったときは、巧妙さよりも明確さを優先してください。

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

コーディングエージェント(Claude Code、Aider、Codexなど)のカスタムタスクによる直接比較。合格率、コスト、時間、一貫性メトリクスを測定

The English summary is being prepared. Showing the original description.

hage-oyaji/everything-claude-code-jp-local3Updated Mar 29, 2026

AIエージェントのアクションスペース、ツール定義、オブザベーションフォーマットを設計・最適化し、タスク完了率を向上させる

The English summary is being prepared. Showing the original description.

hage-oyaji/everything-claude-code-jp-local3Updated Mar 29, 2026

評価ファーストの実行、分解、コスト考慮型モデルルーティングによるエージェンティックエンジニアとしての運用

The English summary is being prepared. Showing the original description.

hage-oyaji/everything-claude-code-jp-local3Updated Mar 29, 2026

AIエージェントが実装出力の大部分を生成するチームのためのエンジニアリング運用モデル

The English summary is being prepared. Showing the original description.

hage-oyaji/everything-claude-code-jp-local3Updated Mar 29, 2026

AI支援開発のためのリグレッションテスト戦略。データベース依存なしのサンドボックスモードAPIテスト、自動バグチェックワークフロー、同一モデルがコードの作成とレビューを行う際のAIの盲点を検出するパターン。

The English summary is being prepared. Showing the original description.

hage-oyaji/everything-claude-code-jp-local3Updated Mar 29, 2026

AndroidおよびKotlin Multiplatformプロジェクトのためのクリーンアーキテクチャパターン — モジュール構成、依存関係ルール、UseCase、Repository、データレイヤーパターン

The English summary is being prepared. Showing the original description.

hage-oyaji/everything-claude-code-jp-local3Updated Mar 29, 2026

See all skills by hage-oyaji

Report a problem with this skill