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. 03通过 Protocol 定义结构化接口
  4. 04用守卫条件收窄类型
  5. 05配置 mypy 或 pyright 严格检查

适用场景

  1. 01为现有 Python 代码补充类型提示
  2. 02构建保留类型信息的通用类
  3. 03为接口定义结构化类型
  4. 04在 CI 中逐步启用严格检查

安装

复制下面的命令,在终端中运行。

$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 尽早捕获类型错误。对于现有项目,可通过按模块覆盖逐步启用严格模式。

模式 2:使用现代联合类型语法

Python 3.10+ 提供了更简洁的联合类型语法。

# 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]
  3. 运行严格类型检查 - 在 CI 中使用 mypy --strict
  4. 使用泛型 - 在可复用代码中保留类型信息
  5. 定义协议 - 为接口使用结构化类型
  6. 收窄类型 - 使用类型守卫帮助类型检查器
  7. 约束类型变量 - 将泛型限制为有意义的类型
  8. 创建类型别名 - 为复杂类型赋予有意义的名称
  9. 尽量减少 Any - 使用具体类型或泛型。对于真正动态的数据,或与无类型的第三方代码交互时,Any 是可以接受的
  10. 用类型记录文档 - 类型是强制执行的文档

评论

支持 Markdown