python-type-safety について
Python 開発者向けの型安全スキルです。型注釈、ジェネリクス、プロトコルを使って静的解析時のエラーを減らし、厳格な型チェックの設定方法も扱います。
主な機能
- 01公開 API への型注釈
- 02再利用可能なジェネリックコード
- 03Protocol による構造的インターフェース
- 04ガードによる型の絞り込み
- 05mypy または pyright の厳格チェック設定
活用シーン
- 01既存の Python コードへの型ヒント追加
- 02型情報を保つ再利用可能なクラスの構築
- 03インターフェースの構造的な型定義
- 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 にあります。上記のナビゲーション概要では不十分な場合は、そのファイルを読んでください。
ベストプラクティスのまとめ
- すべての公開 API にアノテーションを付ける - 関数、メソッド、クラス属性
T | Noneを使う -Optional[T]よりもモダンな Union 構文- 厳密な型チェックを実行する - CI で
mypy --strict - ジェネリクスを使う - 再利用可能なコードで型情報を保持する
- プロトコルを定義する - インターフェースのための構造的型付け
- 型を絞り込む - ガードを使って型チェッカーを支援する
- 型変数を制約する - ジェネリクスを意味のある型に制限する
- 型エイリアスを作成する - 複雑な型に意味のある名前を付ける
Anyを最小限にする - 具体的な型またはジェネリクスを使います。Anyは、真に動的なデータや、型付けされていないサードパーティのコードと連携する場合には許容されます- 型でドキュメント化する - 型は強制力のあるドキュメントです
コメント
Markdown 対応