Agent Skills by ALSEL
Anthropic Claudeソフトウェア開発⭐ リポ 0品質スコア 50/100

python-type-safety

型ヒント、ジェネリクス、プロトコル、厳格な型チェックを活用したPythonの型安全性を担当するスキルです。型アノテーションの追加、ジェネリッククラスの実装、構造的インターフェースの定義、またはmypy/pyrightの設定を行う際に使用してください。

description の原文を見る

Python type safety with type hints, generics, protocols, and strict type checking. Use when adding type annotations, implementing generic classes, defining structural interfaces, or configuring mypy/pyright.

SKILL.md 本文

Python 型安全性

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

このスキルを使う場合

  • 既存コードへの型ヒント追加
  • ジェネリック、再利用可能なクラスの作成
  • Protocol を使った構造的インターフェースの定義
  • mypy または pyright の厳密チェック設定
  • 型の絞り込みとガードの理解
  • 型安全な API やライブラリの構築

コア コンセプト

1. 型アノテーション

関数パラメータ、戻り値、変数の期待される型を宣言します。

2. ジェネリック

異なる型間で型情報を保持する再利用可能なコードを記述します。

3. Protocol

継承なしで構造的インターフェースを定義します(型安全ダックタイピング)。

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 を使用して、型エラーを早期に検出します。既存プロジェクトの場合、モジュール単位のオーバーライドを使って段階的に厳密モードを有効化してください。

パターン 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

高度なパターン

パターン 5: ジェネリック リポジトリ

型安全なデータアクセス パターンを作成します。

from typing import TypeVar, Generic
from abc import ABC, abstractmethod

T = TypeVar("T")
ID = TypeVar("ID")

class Repository(ABC, Generic[T, ID]):
    """Generic repository interface."""

    @abstractmethod
    async def get(self, id: ID) -> T | None:
        """Get entity by ID."""
        ...

    @abstractmethod
    async def save(self, entity: T) -> T:
        """Save and return entity."""
        ...

    @abstractmethod
    async def delete(self, id: ID) -> bool:
        """Delete entity, return True if existed."""
        ...

class UserRepository(Repository[User, str]):
    """Concrete repository for Users with string IDs."""

    async def get(self, id: str) -> User | None:
        row = await self._db.fetchrow(
            "SELECT * FROM users WHERE id = $1", id
        )
        return User(**row) if row else None

    async def save(self, entity: User) -> User:
        ...

    async def delete(self, id: str) -> bool:
        ...

パターン 6: TypeVar に制約を付ける

ジェネリック パラメータを特定の型に制限します。

from typing import TypeVar
from pydantic import BaseModel

ModelT = TypeVar("ModelT", bound=BaseModel)

def validate_and_create(model_cls: type[ModelT], data: dict) -> ModelT:
    """Create a validated Pydantic model from dict."""
    return model_cls.model_validate(data)

# Works with any BaseModel subclass
class User(BaseModel):
    name: str
    email: str

user = validate_and_create(User, {"name": "Alice", "email": "a@b.com"})
# user is typed as User

# Type error: str is not a BaseModel subclass
result = validate_and_create(str, {"name": "Alice"})  # Error!

パターン 7: 構造的型付けのための Protocol

継承を必要とせずにインターフェースを定義します。

from typing import Protocol, runtime_checkable

@runtime_checkable
class Serializable(Protocol):
    """Any class that can be serialized to/from dict."""

    def to_dict(self) -> dict:
        ...

    @classmethod
    def from_dict(cls, data: dict) -> "Serializable":
        ...

# User satisfies Serializable without inheriting from it
class User:
    def __init__(self, id: str, name: str) -> None:
        self.id = id
        self.name = name

    def to_dict(self) -> dict:
        return {"id": self.id, "name": self.name}

    @classmethod
    def from_dict(cls, data: dict) -> "User":
        return cls(id=data["id"], name=data["name"])

def serialize(obj: Serializable) -> str:
    """Works with any Serializable object."""
    return json.dumps(obj.to_dict())

# Works - User matches the protocol
serialize(User("1", "Alice"))

# Runtime checking with @runtime_checkable
isinstance(User("1", "Alice"), Serializable)  # True

パターン 8: 一般的な Protocol パターン

再利用可能な構造的インターフェースを定義します。

from typing import Protocol

class Closeable(Protocol):
    """Resource that can be closed."""
    def close(self) -> None: ...

class AsyncCloseable(Protocol):
    """Async resource that can be closed."""
    async def close(self) -> None: ...

class Readable(Protocol):
    """Object that can be read from."""
    def read(self, n: int = -1) -> bytes: ...

class HasId(Protocol):
    """Object with an ID property."""
    @property
    def id(self) -> str: ...

class Comparable(Protocol):
    """Object that supports comparison."""
    def __lt__(self, other: "Comparable") -> bool: ...
    def __le__(self, other: "Comparable") -> bool: ...

パターン 9: 型エイリアス

意味のある型名を作成します。

注: type Alias = ... ステートメント構文(PEP 695)は Python 3.12 で導入されました。3.10/3.11 を含む以前のバージョンをターゲットとするプロジェクトでは、TypeAlias アノテーション(PEP 613、Python 3.10 以降で利用可能)を使用してください。

# Python 3.12+ type statement (PEP 695)
type UserId = str
type UserDict = dict[str, Any]

# Python 3.12+ type statement with generics (PEP 695)
type Handler[T] = Callable[[Request], T]
type AsyncHandler[T] = Callable[[Request], Awaitable[T]]
# Python 3.10-3.11 style (needed for broader compatibility)
from typing import TypeAlias
from collections.abc import Callable, Awaitable

UserId: TypeAlias = str
Handler: TypeAlias = Callable[[Request], Response]
# Usage
def register_handler(path: str, handler: Handler[Response]) -> None:
    ...

パターン 10: Callable 型

関数パラメータとコールバックに型を付けます。

from collections.abc import Callable, Awaitable

# Sync callback
ProgressCallback = Callable[[int, int], None]  # (current, total)

# Async callback
AsyncHandler = Callable[[Request], Awaitable[Response]]

# With named parameters (using Protocol)
class OnProgress(Protocol):
    def __call__(
        self,
        current: int,
        total: int,
        *,
        message: str = "",
    ) -> None: ...

def process_items(
    items: list[Item],
    on_progress: ProgressCallback | None = None,
) -> list[Result]:
    for i, item in enumerate(items):
        if on_progress:
            on_progress(i, len(items))
        ...

設定

厳密モード チェックリスト

mypy --strict コンプライアンスの場合:

# pyproject.toml
[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
warn_unused_ignores = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
no_implicit_optional = true

段階的導入の目標:

  • すべての関数パラメータにアノテーション
  • すべての戻り値型にアノテーション
  • クラス属性にアノテーション
  • Any 使用を最小化(本当に動的なデータの場合は許容)
  • ジェネリック コレクションは型パラメータを使用(list ではなく list[str]

既存コードベースの場合、# mypy: strict を使うか、pyproject.toml でモジュール単位のオーバーライドを設定して、モジュール単位で厳密モードを有効化します。

ベスト プラクティス サマリー

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

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
wshobson
リポジトリ
wshobson/agents
ライセンス
MIT
最終更新
不明

Source: https://github.com/wshobson/agents / ライセンス: MIT

関連スキル

汎用ソフトウェア開発⭐ リポ 39,967

doubt-driven-development

重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 1,175

apprun-skills

TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。

by yysun
OpenAIソフトウェア開発⭐ リポ 797

desloppify

コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。

by Git-on-my-level
汎用ソフトウェア開発⭐ リポ 39,967

debugging-and-error-recovery

テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

test-driven-development

テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

incremental-implementation

変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。

by addyosmani
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: wshobson · wshobson/agents · ライセンス: MIT