Auto-Pilot / 全自动
更新于 a month ago

python-best-practices

00xBigBoss
0.0k
0xBigBoss/claude-code/.claude/skills/python-best-practices
80
Agent 评分

💡 摘要

一份关于现代Python类型优先开发模式的综合指南与规范,涵盖数据类、联合类型和协议等。

🎯 适合人群

正在采用类型提示的Python开发者构建健壮API的后端工程师执行代码最佳实践的审查者建立团队标准的技术负责人

🤖 AI 吐槽:这是一本优秀的风格指南,但把它称为‘技能’,就像把食谱当作厨房电器来卖一样。

安全分析中风险

README提倡从环境变量加载配置(如API密钥),这是最佳实践。然而,它没有明确警告禁止记录或序列化这些密钥,这是一个常见风险。缓解措施:确保密钥值永远不会被打印、记录或包含在错误信息中。


name: python-best-practices description: Provides Python patterns for type-first development with dataclasses, discriminated unions, NewType, and Protocol. Must use when reading or writing Python files.

Python Best Practices

Type-First Development

Types define the contract before implementation. Follow this workflow:

  1. Define data models - dataclasses, Pydantic models, or TypedDict first
  2. Define function signatures - parameter and return type hints
  3. Implement to satisfy types - let the type checker guide completeness
  4. Validate at boundaries - runtime checks where data enters the system

Make Illegal States Unrepresentable

Use Python's type system to prevent invalid states at type-check time.

Dataclasses for structured data:

from dataclasses import dataclass from datetime import datetime @dataclass(frozen=True) class User: id: str email: str name: str created_at: datetime @dataclass(frozen=True) class CreateUser: email: str name: str # Frozen dataclasses are immutable - no accidental mutation

Discriminated unions with Literal:

from dataclasses import dataclass from typing import Literal @dataclass class Idle: status: Literal["idle"] = "idle" @dataclass class Loading: status: Literal["loading"] = "loading" @dataclass class Success: status: Literal["success"] = "success" data: str @dataclass class Failure: status: Literal["error"] = "error" error: Exception RequestState = Idle | Loading | Success | Failure def handle_state(state: RequestState) -> None: match state: case Idle(): pass case Loading(): show_spinner() case Success(data=data): render(data) case Failure(error=err): show_error(err)

NewType for domain primitives:

from typing import NewType UserId = NewType("UserId", str) OrderId = NewType("OrderId", str) def get_user(user_id: UserId) -> User: # Type checker prevents passing OrderId here ... def create_user_id(raw: str) -> UserId: return UserId(raw)

Enums for constrained values:

from enum import Enum, auto class Role(Enum): ADMIN = auto() USER = auto() GUEST = auto() def check_permission(role: Role) -> bool: match role: case Role.ADMIN: return True case Role.USER: return limited_check() case Role.GUEST: return False # Type checker warns if case is missing

Protocol for structural typing:

from typing import Protocol class Readable(Protocol): def read(self, n: int = -1) -> bytes: ... def process_input(source: Readable) -> bytes: # Accepts any object with a read() method return source.read()

TypedDict for external data shapes:

from typing import TypedDict, Required, NotRequired class UserResponse(TypedDict): id: Required[str] email: Required[str] name: Required[str] avatar_url: NotRequired[str] def parse_user(data: dict) -> UserResponse: # Runtime validation needed - TypedDict is structural return UserResponse( id=data["id"], email=data["email"], name=data["name"], )

Module Structure

Prefer smaller, focused files: one class or closely related set of functions per module. Split when a file handles multiple concerns or exceeds ~300 lines. Use __init__.py to expose public API; keep implementation details in private modules (_internal.py). Colocate tests in tests/ mirroring the source structure.

Functional Patterns

  • Use list/dict/set comprehensions and generator expressions over explicit loops.
  • Prefer @dataclass(frozen=True) for immutable data; avoid mutable default arguments.
  • Use functools.partial for partial application; compose small functions over large classes.
  • Avoid class-level mutable state; prefer pure functions that take inputs and return outputs.

Instructions

  • Raise descriptive exceptions for unsupported cases; every code path returns a value or raises. This makes failures debuggable and prevents silent corruption.
  • Propagate exceptions with context using from err; catching requires re-raising or returning a meaningful result. Swallowed exceptions hide root causes.
  • Handle edge cases explicitly: empty inputs, None, boundary values. Include else clauses in conditionals where appropriate.
  • Use context managers for I/O; prefer pathlib and explicit encodings. Resource leaks cause production issues.
  • Add or adjust unit tests when touching logic; prefer minimal repros that isolate the failure.

Examples

Explicit failure for unimplemented logic:

def build_widget(widget_type: str) -> Widget: raise NotImplementedError(f"build_widget not implemented for type: {widget_type}")

Propagate with context to preserve the original traceback:

try: data = json.loads(raw) except json.JSONDecodeError as err: raise ValueError(f"invalid JSON payload: {err}") from err

Exhaustive match with explicit default:

def process_status(status: str) -> str: match status: case "active": return "processing" case "inactive": return "skipped" case _: raise ValueError(f"unhandled status: {status}")

Debug-level tracing with namespaced logger:

import logging logger = logging.getLogger("myapp.widgets") def create_widget(name: str) -> Widget: logger.debug("creating widget: %s", name) widget = Widget(name=name) logger.debug("created widget id=%s", widget.id) return widget

Configuration

  • Load config from environment variables at startup; validate required values before use. Missing config should fail immediately.
  • Define a config dataclass or Pydantic model as single source of truth; avoid os.getenv scattered throughout code.
  • Use sensible defaults for development; require explicit values for production secrets.

Examples

Typed config with dataclass:

import os from dataclasses import dataclass @dataclass(frozen=True) class Config: port: int = 3000 database_url: str = "" api_key: str = "" env: str = "development" @classmethod def from_env(cls) -> "Config": database_url = os.environ.get("DATABASE_URL", "") if not database_url: raise ValueError("DATABASE_URL is required") return cls( port=int(os.environ.get("PORT", "3000")), database_url=database_url, api_key=os.environ["API_KEY"], # required, will raise if missing env=os.environ.get("ENV", "development"), ) config = Config.from_env()

Optional: ty

For fast type checking, consider ty from Astral (creators of ruff and uv). Written in Rust, it's significantly faster than mypy or pyright.

Installation and usage:

# Run directly with uvx (no install needed) uvx ty check # Check specific files uvx ty check src/main.py # Install permanently uv tool install ty

Key features:

  • Automatic virtual environment detection (via VIRTUAL_ENV or .venv)
  • Project discovery from pyproject.toml
  • Fast incremental checking
  • Compatible with standard Python type hints

Configuration in pyproject.toml:

[tool.ty] python-version = "3.12"

When to use ty vs alternatives:

  • ty - fastest, good for CI and large codebases (early stage, rapidly evolving)
  • pyright - most complete type inference, VS Code integration
  • mypy - mature, extensive plugin ecosystem
五维分析
清晰度8/10
创新性6/10
实用性9/10
完整性9/10
可维护性8/10
优缺点分析

优点

  • 通过类型安全促进健壮、自文档化的代码。
  • 用清晰的示例涵盖了广泛的现代Python类型功能。
  • 强调诸如不可变性和错误处理等实用模式。

缺点

  • 主要是知识库;缺乏可执行工具或自动化。
  • 假设用户已在使用类型检查器(如mypy, pyright)。
  • 对于Python类型系统的初学者可能过于复杂。

相关技能

pytorch

S
toolCode Lib / 代码库
92/ 100

“它是深度学习的瑞士军刀,但祝你好运能从47种安装方法里找到那个不会搞崩你系统的那一个。”

agno

S
toolCode Lib / 代码库
90/ 100

“它承诺成为智能体领域的Kubernetes,但得看开发者有没有耐心学习又一个编排层。”

nuxt-skills

S
toolCo-Pilot / 辅助式
90/ 100

“这本质上是一份组织良好的小抄,能把你的 AI 助手变成一只 Nuxt 框架的复读机。”

免责声明:本内容来源于 GitHub 开源项目,仅供展示和评分分析使用。

版权归原作者所有 0xBigBoss.