ac-python

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Python Bible (Python 3.14)

Python 宝典 (Python 3.14)

Targets: Python 3.14 · Previous line: Python 3.13 (trailing section) · Tooling: uv · ruff · mypy/ty · prek · pytest
适用版本: Python 3.14 · 上一版本线: Python 3.13(见末尾章节) · 工具链: uv · ruff · mypy/ty · prek · pytest

Version Policy

版本策略

This skill documents one Python line: the current one. Keep it that way when you update it.
  • Main path = the current feature release. Today that is Python 3.14. When 3.15 ships, the main path moves to it in the same edit.
  • Unmarked prose means the current line, and there is no marker form. Python ships features only in a feature release, and the main path always is the current feature release — so nothing in it can post-date the line, and a version suffix would have nothing to qualify. (This is where the sibling
    ac-django
    policy differs: Django adds features within a line, so it needs version markers; Python does not.) Do not write "On Python 3.X+, ..." or "if you are on 3.13" in the main path — a conditional in the main path is the defect this rule exists to stop.
  • Older lines get one trailing section each, at the end of
    SKILL.md
    , and nothing anywhere else — the reference files carry the current line only and get no trailing section of their own. Today that is
    ## Previous line: Python 3.13
    . It carries the diff a reader on that version needs: what is missing, what to use instead, and what to change on upgrade.
  • Research order when refreshing.
    https://docs.python.org/3/whatsnew/
    and the library reference first. Then the sources already cited under Canonical Sources. Blogs and newsletters last, briefly, for what the docs do not cover.
  • Rotation. Each October a new line ships: re-base unmarked prose on it, replace the trailing section with the line being retired, drop stale markers.
本Skill文档仅覆盖一个Python版本线:当前最新版本。更新时请保持这一原则。
  • 主路径 = 当前特性版本。 目前主路径为Python 3.14。当3.15发布后,主路径将在同一次编辑中切换至该版本。
  • 未标注版本的内容均适用于当前版本线,无需额外版本标记。 Python仅在特性版本中发布新功能,而主路径始终对应当前特性版本——因此主路径中的内容不可能晚于当前版本,无需添加版本后缀。(这与同系列的
    ac-django
    规范不同:Django会在同一版本线内新增功能,因此需要版本标记;Python则不需要。)请勿在主路径中编写“在Python 3.X+版本中...”或“如果你使用3.13版本”这类表述——主路径中的条件判断是本规则要避免的问题。
  • 旧版本线仅在
    SKILL.md
    末尾保留一个章节
    ,其他位置不涉及旧版本内容——参考文件仅覆盖当前版本线,也不单独设置旧版本章节。目前旧版本章节为
    ## 上一版本线:Python 3.13
    ,其中包含该版本用户需要了解的差异:缺失的功能、替代方案以及升级时的修改点。
  • 更新文档时的资料查阅顺序。
    https://docs.python.org/3/whatsnew/
    和标准库参考文档优先,其次是“权威来源”章节中列出的资料。最后可简要查阅博客和技术通讯,补充文档未覆盖的内容。
  • 版本更迭。 每年10月会发布新的Python版本线:将未标注版本的内容适配到新版本,将刚退役的版本线内容替换到末尾的旧版本章节,移除过时的标记。

Canonical Sources

权威来源

Reference Files (load as needed)

参考文件(按需加载)

FileCoversWhen to load
references/style-and-typing.md
Style, Pythonic idioms, type annotations, readability rulesWriting or reviewing any Python code
references/oop-and-design.md
OOP patterns, data models, factories, properties, design principlesDesigning classes, data models, module structure
references/testing-and-tooling.md
Testing patterns, pytest setup, tooling (uv/ruff/mypy/prek), quality gatesWriting tests, setting up a project, CI
文件覆盖内容加载时机
references/style-and-typing.md
代码风格、Pythonic惯用写法、类型注解、可读性规则编写或评审任何Python代码时
references/oop-and-design.md
OOP模式、数据模型、工厂模式、属性、设计原则设计类、数据模型、模块结构时
references/testing-and-tooling.md
测试模式、pytest配置、工具链(uv/ruff/mypy/prek)、质量门禁编写测试、搭建项目、配置CI时

Dependencies

依赖

Standalone. No dependencies on other skills.
When used alongside ac-django, provides generic Python guidelines that complement Django-specific patterns.
本Skill独立运行,不依赖其他Skill。
与ac-django搭配使用时,可提供通用Python规范,作为Django专属模式的补充。

Trigger QA (Release Gate)

触发QA(发布门禁)

Before shipping skill changes, validate activation behavior with sample prompts:
  • Should trigger:
    • "Write a CLI script that processes CSV files."
    • "Review this Python class for design issues."
    • "Set up testing for this Python microservice."
  • Should NOT trigger:
    • "Add a Django model field and migration."
    • "Set up git worktrees for a ticket."
    • "Implement project delivery workflow."
If behavior under-triggers or over-triggers, tighten
description
cues before release.
发布Skill变更前,请使用以下示例提示词验证触发行为是否正确:
  • 应当触发:
    • “编写一个处理CSV文件的CLI脚本。”
    • “评审这个Python类的设计问题。”
    • “为这个Python微服务搭建测试体系。”
  • 不应触发:
    • “添加一个Django模型字段和迁移。”
    • “为一个工单配置git worktree。”
    • “实现项目交付工作流。”
如果出现触发不足或过度触发的情况,请在发布前优化
description
中的提示信息。

Example: Adding a new data model

示例:新增数据模型

User says: "Add a
LoanApplication
data model with validation"
  1. Load
    references/oop-and-design.md
    for data model patterns
  2. Load
    references/style-and-typing.md
    for typing conventions
  3. Use a dataclass or attrs/pydantic if the project already uses them
  4. Add full type annotations, use
    @cached_property
    for derived attributes
  5. Name the factory
    build_loan_application(...)
    if needed in tests
  6. Mirror the module path in
    tests/
    for the test file
用户说:“添加一个带校验的
LoanApplication
数据模型”
  1. 加载
    references/oop-and-design.md
    参考数据模型模式
  2. 加载
    references/style-and-typing.md
    参考类型注解规范
  3. 如果项目已使用dataclass、attrs或pydantic,则优先使用
  4. 添加完整的类型注解,派生属性使用
    @cached_property
  5. 如测试需要,工厂函数命名为
    build_loan_application(...)
  6. 测试文件的路径需与
    tests/
    目录下的模块路径保持一致

Prime Directives

核心准则

Pythonic first

Pythonic优先

  • Prefer the idiomatic Python solution over a generic one.
  • Use list comprehensions, walrus operator (
    :=
    ),
    itertools
    ,
    operator
    where they clarify intent.
  • Avoid intermediate variables that are only used once.
  • Prefer t-strings (
    t"..."
    , PEP 750) over f-strings when building SQL, HTML, shell commands, or templates from interpolated values. A t-string evaluates to a
    string.templatelib.Template
    , not a
    str
    : the static text and each
    Interpolation
    stay separable, so a processing function can escape every interpolated value for its target grammar. The safety is in that function — the stdlib ships none, so use a library's or write one. A
    Template
    passed where a
    str
    is expected is an error, not an escape.
  • Use the stdlib
    compression.zstd
    for zstd rather than the third-party
    zstandard
    package.
    compression.lzma
    ,
    compression.bz2
    ,
    compression.gzip
    and
    compression.zlib
    are the preferred import names for those modules too; the originals still work and are not deprecated.
    tarfile
    ,
    zipfile
    and
    shutil
    read and write zstd archives.
  • Omit the brackets in a multi-type
    except
    when there is no
    as
    clause (PEP 758):
    except TimeoutError, ConnectionRefusedError:
    . With
    as
    , the brackets are still required.
  • Never
    return
    ,
    break
    , or
    continue
    out of a
    finally
    block — it swallows the in-flight exception, and the compiler emits a
    SyntaxWarning
    for it (PEP 765).
  • 优先采用符合Python惯用风格的解决方案,而非通用方案。
  • 在能清晰表达意图的场景下,使用列表推导式、海象运算符(
    :=
    )、
    itertools
    、
    operator
    模块。
  • 避免仅使用一次的中间变量。
  • 在构建SQL、HTML、Shell命令或模板时,优先使用t-strings(
    t"..."
    ,PEP 750)而非f-strings。t-string的求值结果是
    string.templatelib.Template
    而非
    str
    :静态文本与每个
    Interpolation
    (插值项)保持分离,因此处理函数可以针对目标语法对每个插值进行转义。安全性取决于处理函数——标准库未提供该函数,因此需要使用第三方库或自行实现。将
    Template
    传入期望
    str
    的场景会报错,而非自动转义。
  • zstd压缩请使用标准库
    compression.zstd
    ,而非第三方
    zstandard
    包。
    compression.lzma
    、
    compression.bz2
    、
    compression.gzip
    和
    compression.zlib
    也是对应模块的推荐导入名称;原导入方式仍然可用,并未被弃用。
    tarfile
    、
    zipfile
    和
    shutil
    支持读写zstd归档文件。
  • 当多类型
    except
    没有
    as
    子句时,可省略括号(PEP 758):
    except TimeoutError, ConnectionRefusedError:
    。如果带有
    as
    子句,仍需使用括号。
  • 绝对不要在
    finally
    块中使用
    return
    、
    break
    或
    continue
    ——这会吞掉正在抛出的异常,编译器会为此发出
    SyntaxWarning
    (PEP 765)。

Types are documentation

类型即文档

  • Full, modern annotations everywhere:
    list[str]
    ,
    str | None
    ,
    dict[str, int]
    .
  • Use the
    type
    statement for recurring complex types.
  • No duck-typing: if you are checking for attribute existence before acting, the type hint is too broad — narrow it.
  • 所有位置都使用完整的现代类型注解:
    list[str]
    、
    str | None
    、
    dict[str, int]
    。
  • 重复出现的复杂类型使用
    type
    语句定义别名。
  • 禁止鸭子类型:如果你需要先检查属性是否存在再执行操作,说明类型注解过于宽泛——请收窄类型范围。

No docstrings — names are the docs

无需docstring——名称即文档

  • Use short, expressive function and variable names.
  • Comment ONLY the non-obvious WHY. Never restate the code; never write a signature-echo docstring.
  • A long comment is a code smell — refactor or rename instead of explaining. Multi-line comments are legit only for a genuine non-obvious why, never to narrate the code.
  • Use vertical whitespace to group related lines.
  • 使用简短、表意清晰的函数名和变量名。
  • 仅对非显而易见的“为什么”添加注释。绝不复述代码内容;绝不编写只是重复函数签名的docstring。
  • 长注释是代码坏味道——请通过重构或重命名来替代解释。多行注释仅适用于真正难以理解的原因说明,绝不能用来逐行讲解代码。
  • 使用空行对相关代码行进行分组。

Clean imports

整洁导入

  • All
    import
    statements at the top of the file.
  • No function-level imports, no
    try...except ImportError
    guards. (Repo-specific conventions may relax this for established circular-import patterns.)
  • Assume all dependencies are installed.
  • 所有
    import
    语句放在文件顶部。
  • 禁止函数级导入,禁止
    try...except ImportError
    防护。(针对已存在的循环导入模式,仓库特定规范可适当放宽此要求。)
  • 默认所有依赖均已安装。

No dirty hacks

禁止肮脏Hack

  • Pick the straightforward solution. If it doesn't exist, reconsider the design.
  • Do not fight third-party frameworks — follow their intended patterns.
  • 选择直接明了的解决方案。如果不存在这样的方案,请重新考虑设计是否合理。
  • 不要与第三方框架对抗——遵循其设计的使用模式。

Review Checklist

评审清单

Style

代码风格

  • no single-use intermediate variables
  • list comprehensions / stdlib idioms used where appropriate
  • vertical whitespace groups related logic
  • 无仅使用一次的中间变量
  • 在合适的场景下使用列表推导式/标准库惯用写法
  • 使用空行对相关逻辑分组

Typing

类型注解

  • full modern annotations on all public functions and methods
  • type
    statement used for complex/recurring types
  • no duck-typing (no
    hasattr
    guards in place of proper types)
  • 所有公共函数和方法都有完整的现代类型注解
  • 复杂/重复出现的类型使用
    type
    语句定义别名
  • 无鸭子类型(不使用
    hasattr
    检查替代正确的类型定义)

Imports

导入

  • all imports at top of file
  • no
    try...except ImportError
    blocks
  • no function-level imports
  • 所有导入都在文件顶部
  • 无
    try...except ImportError
    块
  • 无函数级导入

OOP / Design

面向对象/设计

  • data models are first-class (not plain dicts passed around)
  • factories named
    build_...
  • application logic in methods, not module-scope functions
  • @property
    /
    @cached_property
    for derived attributes
  • 数据模型为一等公民(不使用普通字典传递数据)
  • 工厂函数以
    build_...
    命名
  • 应用逻辑放在方法中,而非模块级函数
  • 派生属性使用
    @property
    /
    @cached_property

Best Practices

最佳实践

  • UTC timezone-aware datetimes throughout
  • boolean params preceded by
    , *,
  • try
    blocks and context managers are minimal (ideally one line each)
  • 所有datetime都使用带UTC时区的感知型对象
  • 布尔参数前添加
     , *,
    (强制关键字参数)
  • try
    块和上下文管理器尽可能小(理想情况下各占一行)

Architectural Health (Module-Level)

架构健康度(模块级)

Apply to full files touched by the diff, not just changed lines:
  • no module with >500 LOC (split by concern)
  • no module with >10 module-level functions (use classes)
  • module-level functions are justified — default is methods on a class
  • no god-module (single file mixing unrelated concerns — CLI wiring + business logic + subprocess management = split)
  • no complexity rule suppressions (
    C901
    ,
    PLR09xx
    ) in
    pyproject.toml
    beyond the
    python-boilerplate
    baseline
  • tests assert behavior through public interfaces, not by patching private functions or asserting subprocess command lists
适用于本次变更涉及的完整文件,而非仅修改的行:
  • 无超过500行的模块(按职责拆分)
  • 无超过10个模块级函数的模块(使用类封装)
  • 模块级函数都有合理理由——默认应使用类的方法
  • 无上帝模块(单个文件混合不相关的职责——CLI接线+业务逻辑+子进程管理=需要拆分)
  • pyproject.toml
    中没有超出
    python-boilerplate
    基线的复杂度规则抑制(
    C901
    、
    PLR09xx
    )
  • 测试通过公共接口断言行为,而非通过patch私有函数或断言子进程命令列表

Testing

测试

Integration-First Testing (Non-Negotiable)

集成测试优先(不可妥协)

Write integration tests for happy paths, unit tests for edge cases. This maximizes confidence per line of test code.
  • Integration tests exercise multiple modules together with real (or near-real) I/O. They catch the bugs that matter most: broken contracts between modules, wrong assumptions about state, ordering issues. Mock only what you cannot control (network, external processes, databases).
  • Unit tests target specific functions in isolation — but only when the function has edge cases worth covering (error handling, boundary values, complex branching). Don't unit-test trivial glue code.
  • Don't duplicate coverage. If a happy path is already covered by an integration test, don't write a unit test for the same path. Unit tests should cover what integration tests cannot reach efficiently (rare error branches, corner cases).
  • E2E tests (browser, full-stack) are separate — they belong in frontend/application test suites, not in library or infrastructure code. Write them when testing user-visible behavior end-to-end.
主流程用集成测试覆盖,边界情况用单元测试覆盖。 这样能最大化每行测试代码带来的信心。
  • 集成测试 会同时运行多个模块,使用真实(或接近真实)的I/O。它们能捕获最重要的bug:模块间契约破坏、状态假设错误、时序问题。仅mock你无法控制的部分(网络、外部进程、数据库)。
  • 单元测试 针对单个函数进行隔离测试——但仅当函数有值得覆盖的边界情况时才使用(错误处理、边界值、复杂分支)。不要为简单的粘合代码编写单元测试。
  • 不要重复覆盖。 如果主流程已经被集成测试覆盖,就不要为同一条路径编写单元测试。单元测试应该覆盖集成测试无法高效触达的场景(罕见错误分支、极端情况)。
  • E2E测试(浏览器、全栈)属于独立范畴——它们属于前端/应用测试套件,而非库或基础设施代码的一部分。仅在需要端到端测试用户可见行为时才编写。

Test Conciseness (Non-Negotiable)

测试简洁性(不可妥协)

Tests must be easy to read and maintain. Verbose tests get skimmed, misunderstood, and copy-pasted without thought.
  • One assertion per concept. A test method should test one behavior. Multiple assertions are fine when they verify different facets of the same behavior.
  • Use fixtures for setup, not copy-paste. Repeated setup code across test methods means a missing fixture or parametrize.
  • Parametrize over copy-paste. When multiple tests differ only in input/output values, use
    @pytest.mark.parametrize
    . Five test methods that differ by one string are one parametrized test.
  • Name tests after the behavior, not the method.
    test_returns_error_when_db_missing
    beats
    test_db_import_3
    .
  • No unnecessary mocks. Only mock what you cannot control (network, clock, external processes). Over-mocking makes tests tautological — they test the mocks, not the code.
  • Flat over nested. Prefer module-level test functions or flat test classes. Deeply nested class hierarchies in tests add complexity without value.
  • Prefer context managers (
    with patch(...)
    ) over
    monkeypatch
    .
    Context managers clearly isolate the scope that needs the mock. Use
    monkeypatch
    only when it genuinely simplifies the test (e.g., env vars,
    chdir
    , patching attributes on fixtures that outlive the test body).
测试必须易于阅读和维护。冗长的测试会被跳过、误解,甚至被不假思索地复制粘贴。
  • 每个概念对应一个断言。 一个测试方法应该只测试一种行为。如果多个断言验证的是同一行为的不同方面,则完全可以接受。
  • 使用fixture做初始化,不要复制粘贴。 不同测试方法中存在重复的初始化代码,说明缺少对应的fixture或参数化测试。
  • 优先参数化,而非复制粘贴。 当多个测试仅输入/输出值不同时,使用
    @pytest.mark.parametrize
    。五个仅差一个字符串的测试方法可以合并为一个参数化测试。
  • 测试按行为命名,而非按方法命名。
    test_returns_error_when_db_missing
    比
    test_db_import_3
    好得多。
  • 不要不必要的mock。 仅mock你无法控制的部分(网络、时钟、外部进程)。过度mock会让测试变得毫无意义——它们测试的是mock,而不是代码本身。
  • 扁平优于嵌套。 优先使用模块级测试函数或扁平的测试类。测试中深层嵌套的类层次只会增加复杂度,没有任何价值。
  • 优先使用上下文管理器(
    with patch(...)
    )而非
    monkeypatch
    。
    上下文管理器能清晰隔离需要mock的作用域。仅当
    monkeypatch
    确实能简化测试时才使用(例如环境变量、
    chdir
    、patch生命周期长于测试体的fixture属性)。

Checklist

清单

  • test file mirrors
    src
    module path
  • test class and method names describe the behavior under test
  • happy path covered by integration test; unit tests cover edge cases
  • no duplicated coverage between integration and unit tests
  • @pytest.mark.parametrize
    used where 3+ tests differ only by input/output
  • fixtures used for repeated setup — no copy-pasted boilerplate
  • mocks only for external boundaries (subprocess, network, clock)
  • 测试文件路径与
    src
    模块路径一致
  • 测试类和方法名描述了被测行为
  • 主流程由集成测试覆盖;单元测试覆盖边界情况
  • 集成测试和单元测试之间无重复覆盖
  • 当3个以上测试仅输入/输出不同时,使用
    @pytest.mark.parametrize
  • 重复初始化使用fixture——无复制粘贴的样板代码
  • 仅在外部边界使用mock(子进程、网络、时钟)

Previous line: Python 3.13

上一版本线:Python 3.13

Everything above targets Python 3.14. On 3.13:
  • No t-strings. Build SQL/HTML with the target library's own parameterisation or escaping (
    cursor.execute(sql, params)
    ,
    markupsafe
    ), never f-string interpolation.
  • No
    compression.zstd
    .
    The third-party
    zstandard
    package is the option;
    tarfile
    /
    zipfile
    /
    shutil
    do not read or write zstd.
  • Annotations are evaluated eagerly.
    from __future__ import annotations
    is still needed for forward references, and there is no
    annotationlib
    — use
    typing.get_type_hints()
    . The main path's ruff config bans that import (
    lint.flake8-tidy-imports.banned-api."__future__.annotations"
    in
    references/testing-and-tooling.md
    ); drop that one entry while the project targets 3.13, and restore it on 3.14.
  • except
    needs brackets
    for multiple types:
    except (TimeoutError, ConnectionRefusedError):
    .
  • Free-threading is experimental, not officially supported, and carries a much larger single-threaded penalty than 3.14's ~5–10%.
  • Pin
    python_version
    /
    python-version
    to
    "3.13"
    in the mypy/ty config while the project targets it.
以上所有内容均适用于Python 3.14。在3.13版本中:
  • 不支持t-strings。 构建SQL/HTML时使用目标库自带的参数化或转义功能(
    cursor.execute(sql, params)
    、
    markupsafe
    ),绝对不要用f-string插值。
  • 无
    compression.zstd
    模块。
    可使用第三方
    zstandard
    包;
    tarfile
    /
    zipfile
    /
    shutil
    不支持读写zstd。
  • 类型注解为立即求值。 前向引用仍需要
    from __future__ import annotations
    ,且没有
    annotationlib
    模块——请使用
    typing.get_type_hints()
    。主路径的ruff配置禁止了该导入(见
    references/testing-and-tooling.md
    中的
    lint.flake8-tidy-imports.banned-api."__future__.annotations"
    );当项目目标版本为3.13时移除该规则,升级到3.14后再恢复。
  • 多类型
    except
    需要括号
    :
    except (TimeoutError, ConnectionRefusedError):
    。
  • 自由线程(free-threading)仍处于实验阶段,未被官方支持,且单线程性能损耗远大于3.14的约5–10%。
  • 当项目目标版本为3.13时,在mypy/ty配置中将
    python_version
    /
    python-version
    固定为
    "3.13"
    。