python-coding-standards
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesepython-coding-standards
Python编码规范
Defaults for writing and editing Python, so every file in a project reads
consistently regardless of which session wrote it. None of this applies to
a snippet written purely to illustrate a concept, with no runnable entry
point, that nobody is going to execute — e.g. a one-off example in prose
showing what a decorator looks like. If you can't tell whether something
has a runnable entry point, assume it does. Everything else — including a
demo script, a one-off, or an example saved to a file — is real code the
rules below apply to.
本规范为Python代码编写与编辑的默认标准,确保项目中所有文件无论由谁编写,风格都保持一致。本规范不适用于仅用于演示概念、无可运行入口、不会被执行的代码片段——例如用于展示装饰器写法的示例代码。若无法判断代码是否有可运行入口,请默认其具备可运行入口。除此之外的所有代码——包括演示脚本、一次性脚本或保存到文件的示例——均属于正式代码,需遵循以下规则。
When to Invoke
适用场景
- About to create or edit a file, or write Python code the user is going to run — except code covered by the illustrative-example exemption above.
.py
- 即将创建或编辑文件,或是编写用户将运行的Python代码——除上述概念演示类代码外。
.py
Core Rules
核心规则
-
[NEVER VIOLATE] Functions the user is going to run get complete type hints. Every parameter and the return type — whether the code ends up in a file or stays in the chat as something to copy-paste and execute; a one-off script is still real code. When editing an existing file, this applies to the function you're adding or touching — don't backfill type hints across the rest of the file unless asked.
-
[NEVER VIOLATE] No global variables. Use instance attributes, closures, or dependency injection instead. The smell this rule targets is a module-level or class-level name that gets mutated after it's defined — whether one function touches it (thekeyword is the textbook case) or several. A constant — module-level or class-level, scalar or a dict/list/tuple that's never reassigned or mutated after definition (
global,MAX_RETRIES = 3) — is not a global variable and is fine, and so is a module-levelDEFAULT_HEADERS = {...}.logger = logging.getLogger(__name__) -
Use, never
logging, for anything diagnostic.print()is acceptable only for a CLI tool's actual user-facing output — the thing the program exists to print, not a debug trace left behind. A standalone script callsprint()once at its entry point (logging.basicConfig(level=logging.INFO, format=...)) — without an explicitif __name__ == "__main__":, the root logger defaults to WARNING andlevel=silently produces no output — a module meant to be imported never callslogger.infoitself, that's the importer's call.basicConfig -
Wrap in try/except, and log the failure, any I/O that can fail for reasons your own code doesn't control: HTTP calls, DB connections, subprocess calls, and file reads/writes. This doesn't cover writing to stdout/stderr (Rule 3'scase) — that doesn't fail for external reasons. Log enough to diagnose without a repro — what was called, and the actual exception, not just "failed".
print() -
Comment the WHY, not the WHAT. Only add a comment when it explains something the code itself can't — a hidden constraint, a non-obvious trade-off, a workaround for a specific bug. A well-named function or variable already says what it does; restating that in a comment is noise that goes stale the moment the code changes.
-
Tooling:+
.venv, PEP 8, Black.requirements.txt
-
【绝对禁止违反】用户将运行的函数必须包含完整的type hints。每个参数和返回值都需要添加类型提示——无论代码最终保存到文件还是留在聊天框供用户复制执行;一次性脚本也属于正式代码。编辑现有文件时,仅需为新增或修改的函数添加类型提示,无需为文件中其他函数补全类型提示,除非用户明确要求。
-
【绝对禁止违反】禁止使用全局变量。请使用实例属性、闭包或依赖注入替代。本规则针对的是模块级或类级别的变量被定义后被修改的情况——无论是单个函数修改(使用关键字是典型案例)还是多个函数修改。常量——模块级或类级别的、定义后从未被重新赋值或修改的标量、字典、列表或元组(例如
global、MAX_RETRIES = 3)——不属于全局变量,是允许使用的;模块级别的DEFAULT_HEADERS = {...}也同样允许。logger = logging.getLogger(__name__) -
所有诊断信息请使用,绝对禁止使用
logging。仅当print()用于CLI工具面向用户的实际输出时才允许使用——即程序存在的目的就是输出该内容,而非遗留的调试痕迹。独立脚本需在入口点(print())处调用一次if __name__ == "__main__":——若未显式指定logging.basicConfig(level=logging.INFO, format=...),根日志器默认级别为WARNING,level=将不会产生任何输出;供导入的模块本身绝不能调用logger.info,该操作应由导入方执行。basicConfig -
所有因外部因素可能失败的I/O操作,需包裹在try/except块中并记录失败信息:包括HTTP请求、数据库连接、子进程调用以及文件读写。本规则不适用于向stdout/stderr写入内容(即规则3中允许的场景)——此类操作不会因外部因素失败。记录的信息需足够用于排查问题,无需重现场景——需记录调用内容以及实际异常信息,而非仅记录“失败”。
print() -
注释需解释“原因”,而非“内容”。仅当代码无法自行解释时才添加注释——例如隐藏的约束、非显而易见的权衡、针对特定Bug的规避方案。命名良好的函数或变量已经能说明其功能,重复内容的注释属于冗余信息,且代码变更后注释会失效。
-
工具链:+
.venv、PEP 8、Black。requirements.txt
Testing
测试要求
- Every piece of logic you write or change — a new script, a new feature, or a bug fix — needs a test that exercises its business logic — the behaviour a caller depends on, not the fact that the function ran. [NEVER VIOLATE] Never hardcode a return value, or assert a tautology, just to make a test pass — this applies to a probe just as much as a formal test.
- Test infra (e.g. ) already exists → write the test first, then the implementation.
pytest - No test infra, but the code lives in an existing project (a repo, a
package — somewhere with a future) → set up rather than inventing a bespoke runner. It's the de facto standard, so any future session or agent already knows how to run it.
pytest - No test infra, and the code really is a standalone one-off with no project to land in → at minimum, write a runnable probe: a short standalone snippet that feeds the new code a known input and checks the actual output against what you expect, not just that it ran without crashing. The probe satisfies this rule, it isn't an exemption from it.
- Project already has its own hand-rolled test/probe setup → don't
silently replace it with . Weigh whether the switch is worth the churn, and if it looks like a real improvement, suggest it to the user instead of doing it unprompted.
pytest
- 编写或修改的每一处逻辑——包括新脚本、新功能或Bug修复——都需要编写测试用例,验证其业务逻辑——即调用方依赖的行为,而非仅验证函数能运行。【绝对禁止违反】绝不能硬编码返回值或断言同义语句来使测试通过——无论是临时测试还是正式测试均需遵守。
- 若项目已存在测试基础设施(例如)→ 先编写测试用例,再实现功能。
pytest - 若项目无测试基础设施,但代码属于现有项目(仓库、包等有后续维护需求的项目)→ 请搭建,而非自定义测试运行器。
pytest是事实上的标准,后续任何会话或Agent都知道如何运行它。pytest - 若项目无测试基础设施,且代码确实是独立的一次性脚本、无后续项目归属→ 至少编写一个可运行的测试探针:一段简短的独立代码片段,向新代码输入已知数据,并验证实际输出是否符合预期,而非仅验证代码能运行而不崩溃。测试探针符合本规则要求,并非豁免项。
- 若项目已有自定义的测试/探针机制→ 请勿擅自替换为。需权衡替换是否值得,若确实是更优方案,请先向用户建议,而非直接修改。
pytest
Design Docs
设计文档
- Design docs, if the project keeps them, go wherever that project's existing
documentation convention already puts them. Don't invent a new location
(e.g. an ad hoc folder) alongside a project that already has one.
_doc/
- 若项目有存放设计文档的惯例,请遵循该惯例存放设计文档。请勿在已有存放位置的项目旁新建位置(例如临时的文件夹)。
_doc/