mcpField
P
python-type-safety

python-type-safety

github.com/wshobson開発41.9k12.8k 回インストール2 週間前に更新
リポジトリ

python-type-safety について

Python 開発者向けの型安全スキルです。型注釈、ジェネリクス、プロトコルを使って静的解析時のエラーを減らし、厳格な型チェックの設定方法も扱います。

主な機能

  1. 01公開 API への型注釈
  2. 02再利用可能なジェネリックコード
  3. 03Protocol による構造的インターフェース
  4. 04ガードによる型の絞り込み
  5. 05mypy または pyright の厳格チェック設定

活用シーン

  1. 01既存の Python コードへの型ヒント追加
  2. 02型情報を保つ再利用可能なクラスの構築
  3. 03インターフェースの構造的な型定義
  4. 04CI での厳格チェックの段階的導入

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wshobson/agents --skill python-type-safety

インストール後、Claude Code で/python-type-safetyを入力して読み込まれたか確認します。

同梱ファイルreferences/details.md

詳細

Python の型安全性

Python の型システムを活用して、静的解析時にエラーを検出します。型アノテーションは、ツールが自動的に検証する強制力のあるドキュメントとして機能します。

このスキルを使う場面

  • 既存のコードに型ヒントを追加するとき
  • ジェネリックで再利用可能なクラスを作成するとき
  • プロトコルを使って構造的インターフェースを定義するとき
  • 厳密なチェックのために mypy や pyright を設定するとき
  • 型の絞り込みとガードを理解したいとき
  • 型安全な API やライブラリを構築するとき

中核となる概念

1. 型アノテーション

関数の引数、戻り値、変数に対して期待される型を宣言します。

2. ジェネリクス

異なる型にまたがって型情報を保持する、再利用可能なコードを書きます。

3. プロトコル

継承を使わずに構造的インターフェースを定義します(型安全性を備えたダックタイピング)。

4. 型の絞り込み

ガードと条件分岐を使って、コードブロック内で型を絞り込みます。

クイックスタート

def get_user(user_id: str) -> User | None:
    """Return type makes 'might not exist' explicit."""
    ...

# Type checker enforces handling None case
user = get_user("123")
if user is None:
    raise UserNotFoundError("123")
print(user.name)  # Type checker knows user is User here

基本的なパターン

パターン 1: すべての公開シグネチャにアノテーションを付ける

すべての公開関数、メソッド、クラスには型アノテーションを付けるべきです。

def get_user(user_id: str) -> User:
    """Retrieve user by ID."""
    ...

def process_batch(
    items: list[Item],
    max_workers: int = 4,
) -> BatchResult[ProcessedItem]:
    """Process items concurrently."""
    ...

class UserRepository:
    def __init__(self, db: Database) -> None:
        self._db = db

    async def find_by_id(self, user_id: str) -> User | None:
        """Return User if found, None otherwise."""
        ...

    async def find_by_email(self, email: str) -> User | None:
        ...

    async def save(self, user: User) -> User:
        """Save and return user with generated ID."""
        ...

CI で mypy --strict または pyright を使用して、型エラーを早期に検出しましょう。既存のプロジェクトでは、モジュールごとのオーバーライドを使って段階的に strict モードを有効にできます。

パターン 2: モダンな Union 構文を使う

Python 3.10 以降では、より簡潔な Union 構文が提供されています。

# Preferred (3.10+)
def find_user(user_id: str) -> User | None:
    ...

def parse_value(v: str) -> int | float | str:
    ...

# Older style (still valid, needed for 3.9)
from typing import Optional, Union

def find_user(user_id: str) -> Optional[User]:
    ...
パターン 3: ガードによる型の絞り込み

条件分岐を使って、型チェッカーのために型を絞り込みます。

def process_user(user_id: str) -> UserData:
    user = find_user(user_id)

    if user is None:
        raise UserNotFoundError(f"User {user_id} not found")

    # Type checker knows user is User here, not User | None
    return UserData(
        name=user.name,
        email=user.email,
    )

def process_items(items: list[Item | None]) -> list[ProcessedItem]:
    # Filter and narrow types
    valid_items = [item for item in items if item is not None]
    # valid_items is now list[Item]
    return [process(item) for item in valid_items]
パターン 4: ジェネリッククラス

型安全で再利用可能なコンテナを作成します。

from typing import TypeVar, Generic

T = TypeVar("T")
E = TypeVar("E", bound=Exception)

class Result(Generic[T, E]):
    """Represents either a success value or an error."""

    def __init__(
        self,
        value: T | None = None,
        error: E | None = None,
    ) -> None:
        if (value is None) == (error is None):
            raise ValueError("Exactly one of value or error must be set")
        self._value = value
        self._error = error

    @property
    def is_success(self) -> bool:
        return self._error is None

    @property
    def is_failure(self) -> bool:
        return self._error is not None

    def unwrap(self) -> T:
        """Get value or raise the error."""
        if self._error is not None:
            raise self._error
        return self._value  # type: ignore[return-value]

    def unwrap_or(self, default: T) -> T:
        """Get value or return default."""
        if self._error is not None:
            return default
        return self._value  # type: ignore[return-value]

# Usage preserves types
def parse_config(path: str) -> Result[Config, ConfigError]:
    try:
        return Result(value=Config.from_file(path))
    except ConfigError as e:
        return Result(error=e)

result = parse_config("config.yaml")
if result.is_success:
    config = result.unwrap()  # Type: Config

詳細な実例とパターン

詳細なセクション(## Advanced Patterns で始まるもの)は references/details.md にあります。上記のナビゲーション概要では不十分な場合は、そのファイルを読んでください。

ベストプラクティスのまとめ

  1. すべての公開 API にアノテーションを付ける - 関数、メソッド、クラス属性
  2. T | None を使う - Optional[T] よりもモダンな Union 構文
  3. 厳密な型チェックを実行する - CI で mypy --strict
  4. ジェネリクスを使う - 再利用可能なコードで型情報を保持する
  5. プロトコルを定義する - インターフェースのための構造的型付け
  6. 型を絞り込む - ガードを使って型チェッカーを支援する
  7. 型変数を制約する - ジェネリクスを意味のある型に制限する
  8. 型エイリアスを作成する - 複雑な型に意味のある名前を付ける
  9. Any を最小限にする - 具体的な型またはジェネリクスを使います。Any は、真に動的なデータや、型付けされていないサードパーティのコードと連携する場合には許容されます
  10. 型でドキュメント化する - 型は強制力のあるドキュメントです

コメント