Token导航 LogoToken导航

Agent Skill · 前端设计

python-engineering(Python engineering 测试)

用于辅助 Python 项目开发、测试、依赖管理和常见框架工作流。它适合让 Agent 阅读 Python 代码、定位测试问题、整理运行命令、生成脚本或分析数据处理逻辑。使用时需要确认项目虚拟环境、依赖版本和测试入口;涉及执行脚本、读写文件、访问数据库或调用外部 API 时,应先明确运行目录和输入输出范围,避免误改生产数据。

python-engineering 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证为 MIT,第三方扫描有未通过项,按安装量在前端设计类的 10,216 个 Skill 里排第 6,633。

总安装 476周安装 12GitHub Stars 3下载 97核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:python-engineering(Python engineering 测试)
来源仓库:https://github.com/gonzaloserrano/dotfiles
仓库路径:skills/python-engineering
安装命令:
npx skills add https://github.com/gonzaloserrano/dotfiles --skill python-engineering
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/gonzaloserrano/dotfiles --skill python-engineering

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

python-engineering 用于辅助 Python 项目开发、测试和依赖管理。适合阅读代码、定位测试问题或生成运行脚本。通过 npx skills add 命令从指定仓库安装并使用该技能。涉及执行脚本或访问数据库时,应先明确运行目录和输入输出范围。

适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/python-engineering

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/gonzaloserrano/dotfiles --skill python-enginee…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

python-engineering 怎么安装?

在终端执行 npx skills add https://github.com/gonzaloserrano/dotfiles --skill python-engineering。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

python-engineering 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

python-engineering 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

python-engineering 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

python-engineering 用的人多吗?

公开数据是累计安装 476 次,近一周安装 12 次,下载 97 次,GitHub 3 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

python-engineering 安全吗?

第三方扫描有未通过项,风险较高。除非你确认过源码,否则不建议直接安装到常用环境。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。

先想清楚的地方

  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理前端设计类任务、又不想每次都手写提示词的人。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
frontend-design

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
python-engineering

Python engineering 测试 · 本页

4763需要联网MIT未通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Python Engineering Excellence

This skill provides comprehensive Python engineering guidelines for modern Python development. Use this when writing or reviewing Python code for production systems, CLI tools, and AI agents.

Core Philosophy

The Zen of Python (Selected)

  1. Explicit is better than implicit - Make intentions clear
  2. Simple is better than complex - Favor straightforward solutions
  3. Readability counts - Code is read more than written
  4. Errors should never pass silently - Handle or propagate errors explicitly
  5. There should be one obvious way to do it - Follow established patterns

Design Principles

  • Pass dependencies explicitly, avoid global state
  • Favor composition over inheritance
  • Keep functions small and focused
  • Make side effects obvious

Project Structure

Standard Layout

project/
  src/
    mypackage/
      __init__.py
      core.py
      cli.py
      agents/
        __init__.py
        graph.py
  tests/
    __init__.py
    test_core.py
    conftest.py
  pyproject.toml
  README.md

Guidelines:

  • Use src/ layout to avoid import confusion
  • One package per project under src/
  • Tests mirror source structure
  • All configuration in pyproject.toml

pyproject.toml (uv)

[project]
name = "mypackage"
version = "0.1.0"
description = "My package description"
requires-python = ">=3.11"
dependencies = [
    "typer>=0.9.0",
    "pydantic>=2.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "pytest-asyncio>=0.23",
    "mypy>=1.8",
]

[project.scripts]
mycli = "mypackage.cli:app"

[tool.ruff]
line-length = 100
target-version = "py311"

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM"]

[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_ignores = true

[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]

Naming Conventions

PEP 8 Rules

# Good
module_name          # modules: lowercase_with_underscores
ClassName            # classes: CamelCase
function_name        # functions: lowercase_with_underscores
variable_name        # variables: lowercase_with_underscores
CONSTANT_NAME        # constants: UPPERCASE_WITH_UNDERSCORES
_private_var         # private: leading underscore
__mangled            # name mangling: double underscore

# Bad
ClassName()          # Don't use for functions
functionName         # Don't use camelCase for functions
VariableName         # Don't use CamelCase for variables

Specific Conventions

# Good - descriptive names
def calculate_total_price(items: list[Item]) -> Decimal:
    ...

user_count = len(users)
is_valid = check_validity(data)

# Good - short names for small scopes
for i, item in enumerate(items):
    process(item)

# Bad - single letters for large scopes
def process(d):  # What is d?
    ...

Boolean Naming

# Good - question-like predicates
is_active = True
has_permission = user.can_edit
should_retry = attempt < max_retries

# Bad
active = True        # Unclear if boolean
permission = True    # Noun, not predicate

Code Organization

Imports

Use import statements for packages and modules, not for individual classes or functions (except from typing and collections.abc).

# Good - grouped and sorted (ruff handles this)
from __future__ import annotations

import asyncio
import os
from pathlib import Path

import httpx
from pydantic import BaseModel

from mypackage.core import process
from mypackage.models import User

# Good - import modules, not individual items
from sound.effects import echo
echo.EchoFilter(...)

# Good - typing symbols can be imported directly
from typing import Any, TypeVar
from collections.abc import Sequence, Mapping

# Good - use aliases when needed
import pandas as pd  # Standard abbreviations OK
from mypackage.submodule import very_long_module as vlm

# Bad - importing individual classes (non-typing)
from sound.effects.echo import EchoFilter

# Bad - ungrouped, relative imports in library code
from .core import process  # Avoid relative imports
import os, sys  # Never multiple imports on one line

Module Structure

# Good - clear __all__ for public API
__all__ = ["Client", "process_data", "DataError"]

class DataError(Exception):
    """Raised when data processing fails."""

class Client:
    """HTTP client for the service."""
    ...

def process_data(data: bytes) -> dict:
    """Process raw data into structured format."""
    ...

# Private helpers below public API
def _validate(data: bytes) -> bool:
    ...

Class Organization

class Service:
    """Service for processing requests."""

    def __init__(self, client: Client, config: Config) -> None:
        self._client = client
        self._config = config

    # Public methods first
    def process(self, request: Request) -> Response:
        data = self._fetch(request)
        return self._transform(data)

    # Private methods after
    def _fetch(self, request: Request) -> bytes:
        ...

    def _transform(self, data: bytes) -> Response:
        ...

Error Handling

Exception Patterns

# Good - custom exceptions with context
class ProcessingError(Exception):
    """Raised when processing fails."""

    def __init__(self, message: str, item_id: str) -> None:
        super().__init__(message)
        self.item_id = item_id

# Good - raise with context
def process(item: Item) -> Result:
    try:
        return transform(item)
    except ValueError as e:
        raise ProcessingError(f"failed to transform: {e}", item.id) from e

# Good - use built-in exceptions appropriately
def set_age(age: int) -> None:
    if age < 0:
        raise ValueError("age must be non-negative")

# Bad - bare except (catches KeyboardInterrupt, SystemExit)
try:
    process(item)
except:  # Never do this
    pass

# Bad - catching Exception without re-raising
try:
    process(item)
except Exception:
    pass  # Silently swallowing errors

# OK - catching Exception only if re-raising or at isolation point
try:
    process(item)
except Exception:
    logger.exception("Processing failed")
    raise  # Re-raise after logging

Assertions

Do not use assert for validation or preconditions—use explicit conditionals:

# Bad - assert can be disabled with -O flag
def process(data: bytes) -> dict:
    assert data, "data required"  # Skipped in optimized mode!
    return parse(data)

# Good - explicit validation
def process(data: bytes) -> dict:
    if not data:
        raise ValueError("data required")
    return parse(data)

# OK - assert in tests (pytest)
def test_process():
    result = process(b"test")
    assert result["status"] == "ok"

Context Managers

# Good - use context managers for cleanup
from contextlib import contextmanager

@contextmanager
def managed_connection(dsn: str):
    conn = connect(dsn)
    try:
        yield conn
    finally:
        conn.close()

# Usage
with managed_connection(dsn) as conn:
    conn.execute(query)

# Good - async context manager
from contextlib import asynccontextmanager

@asynccontextmanager
async def managed_session():
    session = aiohttp.ClientSession()
    try:
        yield session
    finally:
        await session.close()

Guard Clauses

# Good - early returns reduce nesting
def process_user(user: User | None) -> Result:
    if user is None:
        raise ValueError("user required")

    if not user.is_active:
        return Result.inactive()

    if not user.has_permission("process"):
        return Result.forbidden()

    # Main logic at base indentation
    return do_processing(user)

# Bad - deeply nested
def process_user(user: User | None) -> Result:
    if user is not None:
        if user.is_active:
            if user.has_permission("process"):
                return do_processing(user)
            else:
                return Result.forbidden()
        else:
            return Result.inactive()
    else:
        raise ValueError("user required")

Async/Await

Basic Patterns

# Good - async function
async def fetch_data(url: str) -> dict:
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response.json()

# Good - gather for concurrent operations
async def fetch_all(urls: list[str]) -> list[dict]:
    async with httpx.AsyncClient() as client:
        tasks = [client.get(url) for url in urls]
        responses = await asyncio.gather(*tasks)
        return [r.json() for r in responses]

# Bad - sequential when concurrent is possible
async def fetch_all_slow(urls: list[str]) -> list[dict]:
    results = []
    for url in urls:
        data = await fetch_data(url)  # Sequential!
        results.append(data)
    return results

Task Management

# Good - structured concurrency with TaskGroup (Python 3.11+)
async def process_items(items: list[Item]) -> list[Result]:
    results = []
    async with asyncio.TaskGroup() as tg:
        for item in items:
            task = tg.create_task(process_item(item))
            results.append(task)
    return [t.result() for t in results]

# Good - timeout handling
async def fetch_with_timeout(url: str, timeout: float = 30.0) -> dict:
    async with asyncio.timeout(timeout):
        return await fetch_data(url)

Async Context

# Good - async generators
async def stream_results(query: str):
    async with get_connection() as conn:
        async for row in conn.execute(query):
            yield process_row(row)

# Usage
async for result in stream_results(query):
    handle(result)

Type Hints

Gradual Typing Approach

Type hints encouraged but not enforced. Prioritize:

  1. Public API functions and methods
  2. Function signatures (args + return)
  3. Complex data structures
  4. Code that benefits from IDE support
# Good - typed public API
def process_items(items: list[Item], *, strict: bool = False) -> list[Result]:
    """Process items and return results."""
    ...

# OK - internal helper without full typing
def _transform(data):
    # Complex internal logic
    ...

Common Patterns

from typing import TypeVar, Protocol, Callable
from collections.abc import Iterator, Sequence

# Generic types
T = TypeVar("T")

def first(items: Sequence[T]) -> T | None:
    return items[0] if items else None

# Protocols for structural typing
class Processor(Protocol):
    def process(self, data: bytes) -> dict: ...

def run(processor: Processor, data: bytes) -> dict:
    return processor.process(data)

# Callable types
Handler = Callable[[Request], Response]

def with_logging(handler: Handler) -> Handler:
    def wrapper(request: Request) -> Response:
        log(request)
        return handler(request)
    return wrapper

# Union and Optional (use | syntax in 3.10+)
def find_user(user_id: str) -> User | None:
    ...

# TypedDict for structured dicts
from typing import TypedDict

class UserData(TypedDict):
    name: str
    email: str
    age: int | None

Type Narrowing

# Good - type narrowing with isinstance
def process(value: str | int) -> str:
    if isinstance(value, str):
        return value.upper()  # Type narrowed to str
    return str(value)

# Good - assert for narrowing (use sparingly)
def process_user(user: User | None) -> str:
    assert user is not None, "user required"
    return user.name  # Type narrowed to User

Formatting

Line Length and Indentation

  • Maximum 80 characters per line (URLs and long imports excepted)
  • Use 4 spaces for indentation; never tabs
  • Use implicit line continuation inside parentheses, brackets, braces
# Good - implicit continuation with aligned elements
result = some_function(
    argument_one,
    argument_two,
    argument_three,
)

# Good - hanging indent
result = some_function(
    argument_one, argument_two,
    argument_three,
)

# Bad - backslash continuation
result = some_long_function_name() \
    + another_function()

# Good - parentheses for continuation
result = (
    some_long_function_name()
    + another_function()
)

Whitespace

# Good
spam(ham[1], {eggs: 2})
x = 1
dict["key"] = list[index]
def func(default: str = "value") -> None: ...

# Bad - spaces inside brackets
spam( ham[ 1 ], { eggs: 2 } )

# Bad - space before bracket
spam (ham[1])
dict ["key"]

# Good - break at highest syntactic level
if (
    condition_one
    and condition_two
    and condition_three
):
    do_something()

# Bad - break in middle of expression
if (condition_one and
    condition_two):
    do_something()

Blank Lines

  • Two blank lines between top-level definitions (functions, classes)
  • One blank line between method definitions
  • No blank line after def line

Comprehensions

Use comprehensions for simple transformations. Avoid complex comprehensions.

# Good - simple comprehension
squares = [x * x for x in range(10)]
evens = {x for x in numbers if x % 2 == 0}
mapping = {k: v for k, v in pairs}

# Good - generator for large data
total = sum(x * x for x in range(1000000))

# Bad - multiple for clauses (hard to read)
result = [
    (x, y, z)
    for x in range(5)
    for y in range(5)
    for z in range(5)
    if x != y
]

# Good - use nested loops instead
result = []
for x in range(5):
    for y in range(5):
        for z in range(5):
            if x != y:
                result.append((x, y, z))

# Bad - complex conditions in comprehension
result = [transform(x) for x in data if validate(x) and x.enabled and x.value > 0]

# Good - extract to function or use loop
def should_include(x):
    return validate(x) and x.enabled and x.value > 0

result = [transform(x) for x in data if should_include(x)]

Strings

Formatting

Use f-strings for interpolation. For logging, use % format with pattern strings.

# Good - f-strings for general use
message = f"Processing {item.name} (id={item.id})"

# Good - logging with % patterns (deferred formatting)
logger.info("Processing %s (id=%s)", item.name, item.id)

# Bad - f-strings in logging (always formatted even if not logged)
logger.debug(f"Data: {expensive_repr(data)}")

# Good - join for concatenation in loops
parts = []
for item in items:
    parts.append(str(item))
result = ", ".join(parts)

# Or simply:
result = ", ".join(str(item) for item in items)

# Bad - += concatenation in loop
result = ""
for item in items:
    result += str(item) + ", "  # Creates many intermediate strings

Multiline Strings

# Good - textwrap.dedent for indented multiline
import textwrap

long_string = textwrap.dedent("""\
    First line
    Second line
    Third line
""")

# Good - implicit concatenation
message = (
    "This is a very long message that needs "
    "to be split across multiple lines for "
    "readability purposes."
)

Configuration

Pydantic Settings

from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_prefix="MYAPP_",
        env_file=".env",
    )

    database_url: str
    api_key: str
    debug: bool = False
    max_workers: int = 4

# Usage
settings = Settings()  # Loads from env vars / .env

CLI Arguments with Typer

import typer
from typing import Annotated

app = typer.Typer()

@app.command()
def main(
    input_file: Annotated[Path, typer.Argument(help="Input file path")],
    output: Annotated[Path, typer.Option("--output", "-o")] = Path("out.json"),
    verbose: Annotated[bool, typer.Option("--verbose", "-v")] = False,
) -> None:
    """Process input file and write results."""
    if verbose:
        print(f"Processing {input_file}")

    result = process(input_file)
    output.write_text(json.dumps(result))

if __name__ == "__main__":
    app()

Testing

Pytest Basics

# tests/test_core.py
import pytest
from mypackage.core import process, ProcessingError

def test_process_valid_input():
    result = process(b"valid data")
    assert result["status"] == "ok"

def test_process_empty_input():
    with pytest.raises(ProcessingError) as exc_info:
        process(b"")
    assert "empty" in str(exc_info.value)

Fixtures

# tests/conftest.py
import pytest
from mypackage import Client, Config

@pytest.fixture
def config() -> Config:
    return Config(api_url="http://test", timeout=1.0)

@pytest.fixture
def client(config: Config) -> Client:
    return Client(config)

# Fixture with cleanup
@pytest.fixture
def temp_db(tmp_path):
    db_path = tmp_path / "test.db"
    db = create_database(db_path)
    yield db
    db.close()

# Async fixtures
@pytest.fixture
async def async_client():
    async with httpx.AsyncClient() as client:
        yield client

Parametrized Tests

@pytest.mark.parametrize(
    "input_data,expected",
    [
        (b"hello", {"word": "hello", "length": 5}),
        (b"world", {"word": "world", "length": 5}),
        (b"", None),
    ],
    ids=["hello", "world", "empty"],
)
def test_parse(input_data: bytes, expected: dict | None):
    result = parse(input_data)
    assert result == expected

Mocking

from unittest.mock import Mock, AsyncMock, patch

def test_with_mock():
    mock_client = Mock()
    mock_client.fetch.return_value = {"data": "test"}

    service = Service(client=mock_client)
    result = service.process()

    mock_client.fetch.assert_called_once()
    assert result == {"data": "test"}

# Async mock
async def test_async_service():
    mock_client = AsyncMock()
    mock_client.fetch.return_value = {"data": "test"}

    service = AsyncService(client=mock_client)
    result = await service.process()

    assert result == {"data": "test"}

# Patching
@patch("mypackage.core.external_api")
def test_with_patch(mock_api):
    mock_api.return_value = "mocked"
    result = function_using_api()
    assert result == "mocked"

CLI Development

Typer Application Structure

# src/mypackage/cli.py
import typer
from rich.console import Console

app = typer.Typer(help="My CLI application")
console = Console()

@app.command()
def init(
    name: str,
    force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing"),
) -> None:
    """Initialize a new project."""
    if Path(name).exists() and not force:
        console.print(f"[red]Error:[/red] {name} already exists")
        raise typer.Exit(1)

    create_project(name)
    console.print(f"[green]Created[/green] {name}")

@app.command()
def run(
    config: Path = typer.Option(Path("config.yaml"), "--config", "-c"),
) -> None:
    """Run the application."""
    settings = load_config(config)
    execute(settings)

if __name__ == "__main__":
    app()

Subcommands

# Main app with subcommands
app = typer.Typer()
db_app = typer.Typer(help="Database commands")
app.add_typer(db_app, name="db")

@db_app.command("migrate")
def db_migrate():
    """Run database migrations."""
    ...

@db_app.command("seed")
def db_seed():
    """Seed database with test data."""
    ...

# Usage: mycli db migrate

AI Agents / LangGraph

State Management

from typing import Annotated, TypedDict
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages

class AgentState(TypedDict):
    messages: Annotated[list, add_messages]
    context: dict
    next_step: str | None

def create_agent() -> StateGraph:
    graph = StateGraph(AgentState)

    graph.add_node("process", process_node)
    graph.add_node("decide", decision_node)
    graph.add_node("execute", execute_node)

    graph.add_edge("process", "decide")
    graph.add_conditional_edges(
        "decide",
        route_decision,
        {"execute": "execute", "end": "__end__"},
    )
    graph.add_edge("execute", "process")

    graph.set_entry_point("process")
    return graph.compile()

Tool Definitions

from langchain_core.tools import tool

@tool
def search_database(query: str) -> list[dict]:
    """Search the database for matching records.

    Args:
        query: Search query string

    Returns:
        List of matching records
    """
    return db.search(query)

@tool
async def fetch_url(url: str) -> str:
    """Fetch content from a URL.

    Args:
        url: URL to fetch

    Returns:
        Page content as text
    """
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response.text

Node Functions

from langchain_core.messages import HumanMessage, AIMessage

async def process_node(state: AgentState) -> AgentState:
    """Process incoming messages and update context."""
    last_message = state["messages"][-1]

    if isinstance(last_message, HumanMessage):
        # Process user input
        context = await analyze_message(last_message.content)
        return {"context": context}

    return {}

def decision_node(state: AgentState) -> AgentState:
    """Decide next action based on context."""
    context = state["context"]

    if context.get("needs_execution"):
        return {"next_step": "execute"}

    return {"next_step": "end"}

def route_decision(state: AgentState) -> str:
    """Route based on decision."""
    return state.get("next_step", "end")

Dependency Injection

Constructor Injection

# Good - dependencies passed explicitly
class UserService:
    def __init__(self, db: Database, cache: Cache, logger: Logger) -> None:
        self._db = db
        self._cache = cache
        self._logger = logger

    def get_user(self, user_id: str) -> User | None:
        if cached := self._cache.get(user_id):
            return cached

        user = self._db.find_user(user_id)
        if user:
            self._cache.set(user_id, user)
        return user

# Bad - hidden dependencies
class UserService:
    def get_user(self, user_id: str) -> User | None:
        return global_db.find_user(user_id)  # Hidden dependency

Factory Functions

def create_service(config: Config) -> Service:
    """Create service with all dependencies configured."""
    db = Database(config.database_url)
    cache = RedisCache(config.redis_url)
    logger = setup_logger(config.log_level)

    return Service(db=db, cache=cache, logger=logger)

# In tests
def create_test_service() -> Service:
    return Service(
        db=InMemoryDatabase(),
        cache=DictCache(),
        logger=NullLogger(),
    )

Main Entry Point

Always guard module-level code to prevent execution on import:

# Good - guarded entry point
def main() -> None:
    """Application entry point."""
    config = load_config()
    result = process(config)
    print(result)

if __name__ == "__main__":
    main()

# With CLI framework (typer)
import typer

app = typer.Typer()

@app.command()
def main(config: Path = typer.Option(...)) -> None:
    """Process with configuration."""
    ...

if __name__ == "__main__":
    app()

Anti-patterns to Avoid

Mutable Default Arguments

# Bad - mutable default shared across calls
def append_item(item, items=[]):
    items.append(item)
    return items

# Good - use None and create new list
def append_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

Bare Except

# Bad - catches everything including KeyboardInterrupt
try:
    process()
except:
    pass

# Good - catch specific exceptions
try:
    process()
except ProcessingError as e:
    logger.error(f"Processing failed: {e}")
    raise

Star Imports

# Bad - pollutes namespace, unclear origins
from module import *

# Good - explicit imports
from module import SpecificClass, specific_function

Overusing Inheritance

# Bad - deep inheritance hierarchy
class Animal: ...
class Mammal(Animal): ...
class Dog(Mammal): ...
class GermanShepherd(Dog): ...

# Good - composition and protocols
class Animal(Protocol):
    def speak(self) -> str: ...

class Dog:
    def __init__(self, breed: str) -> None:
        self.breed = breed

    def speak(self) -> str:
        return "woof"

God Classes

# Bad - class doing too much
class Application:
    def connect_database(self): ...
    def send_email(self): ...
    def process_payment(self): ...
    def generate_report(self): ...
    def authenticate_user(self): ...

# Good - single responsibility
class DatabaseConnection: ...
class EmailService: ...
class PaymentProcessor: ...
class ReportGenerator: ...
class AuthService: ...

Avoid Power Features

Avoid metaclasses, dynamic attribute access via __getattr__, bytecode manipulation, and reflection tricks. Use simpler alternatives.

# Bad - metaclass for simple use case
class SingletonMeta(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

# Good - module-level instance or factory function
_instance = None

def get_instance() -> Service:
    global _instance
    if _instance is None:
        _instance = Service()
    return _instance

Avoid staticmethod

Use module-level functions instead of @staticmethod:

# Bad - staticmethod
class StringUtils:
    @staticmethod
    def clean(text: str) -> str:
        return text.strip().lower()

# Good - module-level function
def clean_text(text: str) -> str:
    return text.strip().lower()

Boolean Evaluation Pitfalls

# Good - explicit None check
if value is not None:
    process(value)

# Bad - falsy check when 0 or "" are valid
if value:  # Fails for value=0 or value=""
    process(value)

# Good - explicit comparison for sequences
if len(items) == 0:
    return default

# OK - implicit boolean for sequences (when falsy means empty)
if not items:
    return default

Documentation

Docstrings

def process_data(
    data: bytes,
    *,
    encoding: str = "utf-8",
    strict: bool = False,
) -> dict:
    """Process raw bytes into structured data.

    Args:
        data: Raw bytes to process
        encoding: Text encoding to use
        strict: If True, raise on invalid data

    Returns:
        Parsed data as dictionary

    Raises:
        ProcessingError: If data is invalid and strict=True

    Example:
        >>> result = process_data(b'{"key": "value"}')
        >>> result["key"]
        'value'
    """
    ...

Class Docstrings

class DataProcessor:
    """Process and transform data from various sources.

    This class handles reading data from files or URLs,
    validating the format, and transforming it into
    the required output structure.

    Attributes:
        config: Processor configuration
        stats: Processing statistics

    Example:
        >>> processor = DataProcessor(Config())
        >>> result = processor.process(data)
    """

    def __init__(self, config: Config) -> None:
        """Initialize processor with configuration.

        Args:
            config: Processor configuration object
        """
        self.config = config
        self.stats = Stats()

Tooling Workflow

uv Commands

# Create new project
uv init myproject
cd myproject

# Add dependencies
uv add httpx pydantic typer

# Add dev dependencies
uv add --dev pytest pytest-asyncio mypy ruff

# Sync dependencies
uv sync

# Run commands in venv
uv run python script.py
uv run pytest
uv run mypy src/

# Build package
uv build

ruff Commands

# Check for issues
uv run ruff check .

# Fix auto-fixable issues
uv run ruff check --fix .

# Format code
uv run ruff format .

# Check formatting without changes
uv run ruff format --check .

mypy Commands

# Type check
uv run mypy src/

# Strict mode (if desired)
uv run mypy --strict src/

# Generate stub files
uv run stubgen -p mypackage

pytest Commands

# Run all tests
uv run pytest

# Verbose with output
uv run pytest -v -s

# Run specific test
uv run pytest tests/test_core.py::test_process

# Run with coverage
uv run pytest --cov=mypackage --cov-report=html

# Run async tests (with pytest-asyncio)
uv run pytest  # asyncio_mode = "auto" in pyproject.toml

Pre-commit Workflow

# 1. Format
uv run ruff format .

# 2. Lint and fix
uv run ruff check --fix .

# 3. Type check
uv run mypy src/

# 4. Run tests
uv run pytest

# 5. All checks pass, ready to commit

Additional Resources


Remember: These guidelines support writing clear, maintainable Python code. Adapt them to your specific context, but always favor readability, explicitness, and simplicity.

平台分布

Claude Code

31.73%
按下载量换算31

windsurf

20.64%
按下载量换算20

trae

15.72%
按下载量换算15

OpenCode

11.77%
按下载量换算11

Codex

8.23%
按下载量换算8

Antigravity

3.26%
按下载量换算3

安全审计

Gen Agent Trust Hub

未通过

Socket

通过

Snyk

可疑

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。

继续浏览同类 Skills