stand-py
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePython Code Standards
Python编码规范
Standards for Python code (>= 3.11).
适用于Python代码(>= 3.11版本)的规范。
Runtime
运行环境
- All Python code should be run with
uv
- 所有Python代码应使用运行
uv
PEP Compliance
PEP合规要求
- PEP 604: Use union types as (not
X | Y)Union[X, Y] - PEP 673: Use type for self-referential types
Self
- PEP 604:使用作为联合类型(而非
X | Y)Union[X, Y] - PEP 673:使用类型表示自引用类型
Self
Required Elements
必备元素
- Type hints on ALL function parameters
- Return types on ALL functions
- Docstrings in Google Style Guide format for:
- Modules
- Classes
- Functions/methods
- 所有函数参数必须添加类型提示
- 所有函数必须声明返回类型
- 以下元素需采用Google风格指南格式编写文档字符串:
- 模块
- 类
- 函数/方法
Docstring Format (Google Style)
文档字符串格式(Google风格)
python
def function_with_docstring(
param1: str,
param2: int,
) -> bool:
"""Short description of function.
Longer description if needed.
Args:
param1: Description of param1.
param2: Description of param2.
Returns:
Description of return value.
Raises:
ValueError: When something is wrong.
"""python
def function_with_docstring(
param1: str,
param2: int,
) -> bool:
"""函数简短描述。
如需详细说明可在此处补充。
参数:
param1: param1的描述。
param2: param2的描述。
返回:
返回值的描述。
异常:
ValueError: 当出现错误时抛出。
"""Design Patterns
设计模式
- Use for structured records with fixed fields and named attributes
dataclasses - Use for dynamic key-value aggregation with automatic defaults
collections.defaultdict - Choose based on the use case: typed record-like object () vs map with default values (
dataclass)defaultdict - Each dataclass should be in a separate file
- String Enums should use with
StrEnumauto() - Use with all Enums where it makes sense
auto()
- 使用创建具有固定字段和命名属性的结构化记录
dataclasses - 使用实现带自动默认值的动态键值聚合
collections.defaultdict - 根据使用场景选择:类型化记录类对象() vs 带默认值的映射(
dataclass)defaultdict - 每个dataclass应单独放在一个文件中
- 字符串枚举应使用带的
auto()StrEnum - 在合理的情况下,所有枚举都应使用
auto()
Idioms
编程惯例
Prefer Python-native constructs over verbose cross-language patterns.
-
/
any()over flag-and-break loops:all()python# Don't found = False for p in paths: if p.exists(): found = True break # Do found = any(p.exists() for p in paths) -
over key-in checks:
dict.get()python# Don't if name in registry: return registry[name] return None # Do return registry.get(name) -
over
pathlib— never mix the two in one codebase:os.pathpython# Don't root = os.path.dirname(os.path.dirname(os.path.dirname(path))) # Do root = Path(path).parents[2] -
Truthiness over length checks:python
# Don't if len(items) == 0: ... # Do if not items: ... -
Comprehensions over loop-append for simple transforms:python
# Don't names = [] for user in users: names.append(user.name) # Do names = [user.name for user in users] -
Direct boolean returns:python
# Don't if count > limit: return True return False # Do return count > limit -
over a
contextlib.suppress(SomeError)/tryblockexcept SomeError: pass -
Reach for/
itertools(functools,chain,pairwise,cache) when they replace hand-rolled loop logicreduce
优先使用Python原生语法,而非冗长的跨语言模式。
-
使用/
any()替代标志位+中断循环:all()python# 不推荐 found = False for p in paths: if p.exists(): found = True break # 推荐 found = any(p.exists() for p in paths) -
使用替代键存在性检查:
dict.get()python# 不推荐 if name in registry: return registry[name] return None # 推荐 return registry.get(name) -
使用替代
pathlib— 严禁在同一代码库中混合使用两者:os.pathpython# 不推荐 root = os.path.dirname(os.path.dirname(os.path.dirname(path))) # 推荐 root = Path(path).parents[2] -
使用真值判断替代长度检查:python
# 不推荐 if len(items) == 0: ... # 推荐 if not items: ... -
使用推导式替代循环+追加操作实现简单转换:python
# 不推荐 names = [] for user in users: names.append(user.name) # 推荐 names = [user.name for user in users] -
直接返回布尔值:python
# 不推荐 if count > limit: return True return False # 推荐 return count > limit -
使用替代
contextlib.suppress(SomeError)/try代码块except SomeError: pass -
当可替代手写循环逻辑时,优先使用/
itertools中的工具(如functools、chain、pairwise、cache)reduce
Formatting Rules
格式规则
-
More than 1 arg/param requires a trailing comma:python
# Good def foo(bar: str, baz: int,) -> None: # Bad def foo(bar: str, baz: int) -> None: -
Be explicit with function calls when more than 1 arg:python
# Good foo(bar=bar, baz=baz) # Bad foo(bar, baz) -
Single arg can be positional:python
# OK foo(bar)
-
当参数/实参数量超过1个时,需添加末尾逗号:python
# 规范写法 def foo(bar: str, baz: int,) -> None: # 不规范写法 def foo(bar: str, baz: int) -> None: -
当实参数量超过1个时,函数调用需显式指定关键字参数:python
# 规范写法 foo(bar=bar, baz=baz) # 不规范写法 foo(bar, baz) -
单个实参可使用位置参数:python
# 允许写法 foo(bar)
Linting
代码检查
Follow the skill for linting and formatting workflow.
lint遵循技能中的代码检查与格式化流程。
lintIgnoring Issues
忽略问题规则
Follow the skill ignore policy (Rules section): fix the root cause
first; if suppression is genuinely required, use the narrowest possible ignore
(specific rule code, single line) with an inline justification; blanket or
file-level ignores require a documented exception.
lintPython-specific: Bandit requires an inline or
on the same line as the flagged statement (preceding-line is silently
ignored by Bandit). See the skill for other tool ignore configurations (e.g. mypy
may use a preceding-line comment plus inline ):
# nosec# nosec BXXX - reason# noseclint# type: ignorepython
undefined遵循技能中的忽略策略(规则部分):优先修复根本问题;若确实需要抑制,使用最窄范围的忽略(特定规则代码、单行)并添加行内说明;全局或文件级忽略需提供文档化的例外说明。
lintPython特定规则:Bandit要求在标记语句的同一行添加行内或(行前的会被Bandit忽略)。其他工具的忽略配置请参考技能(例如mypy可使用行前注释加行内):
# nosec# nosec BXXX - reason# noseclint# type: ignorepython
undefinedDon't - blanket, unjustified ignore
不推荐 - 全局无理由忽略
subprocess.run(["validate.sh"]) # nosec
subprocess.run(["validate.sh"]) # nosec
Do - narrowest code, inline justification
推荐 - 最窄规则代码+行内说明
subprocess.run(["validate.sh"]) # nosec B603 - fixed argv list; no shell
Additional Python-specific note: docstrings are required even for tests — no
exceptions.subprocess.run(["validate.sh"]) # nosec B603 - 固定argv列表;未使用shell
Python额外注意事项:即使是测试代码也必须编写文档字符串 — 无例外情况。Testing (Pytest)
测试规范(Pytest)
- NEVER use unittest style or test classes
- Use pytest-style test functions only
- Leverage for shared fixtures
conftest.py - Use fixtures for reusable setup/teardown
- Use to reduce duplication
@pytest.mark.parametrize - ALWAYS use for assertions — never bare
assertpystatements. Keepassertfor exception contexts (assertpy does not replace it)pytest.raises
python
undefined- 严禁使用unittest风格或测试类
- 仅使用pytest风格的测试函数
- 利用定义共享夹具(fixtures)
conftest.py - 使用夹具实现可复用的初始化/清理逻辑
- 使用减少代码重复
@pytest.mark.parametrize - 必须使用进行断言 — 绝不使用原生
assertpy语句。保留assert用于异常场景(assertpy无法替代该功能)pytest.raises
python
undefinedDon't
不推荐
assert result.count == 3
assert "drift" in output
assert result.count == 3
assert "drift" in output
Do
推荐
from assertpy import assert_that
assert_that(result.count).is_equal_to(3)
assert_that(output).contains("drift")
```pythonfrom assertpy import assert_that
assert_that(result.count).is_equal_to(3)
assert_that(output).contains("drift")
```pythonWRONG
错误写法
class TestFoo(unittest.TestCase):
def test_bar(self):
...
class TestFoo(unittest.TestCase):
def test_bar(self):
...
CORRECT
正确写法
def test_foo_bar() -> None:
"""Verify foo handles bar correctly."""
...
undefineddef test_foo_bar() -> None:
"""验证foo正确处理bar场景。"""
...
undefinedWiring vs. Behavior
关联测试 vs 行为测试
A test that asserts where is also defined in source
code is duplication, and produces silent drift the moment either side changes.
field == "literal""literal"- Wiring tests (does X read from canonical Y) — source from the constant. Better still, ask whether the test is just restating the constant's value; if so, delete it. The codegen / source-of-truth machinery is what guarantees that wiring, not a per-consumer assertion.
- Behavior tests (does X meet a fixed external contract — protocol versions, public API shapes, business rules) — hardcode the literal. The literal is the contract.
- Fixture data and parser inputs are not wiring — keep those literal. They represent the world being modeled, not internal state.
Parametrize IDs should describe the case under test (), never encode
mutable data values () — IDs that change with every dependency
bump are a smell.
attr=min_versionmin_version_is_0.43.0若测试断言,而同时在源代码中定义,这属于重复代码,且一旦任意一方变更会导致隐性偏差。
field == "literal""literal"- 关联测试(X是否从标准Y读取数据)—— 从常量中取值。更好的方式是判断该测试是否只是重复常量值;若是,则删除该测试。代码生成/可信源机制可保证关联关系,无需每个消费者都添加断言。
- 行为测试(X是否符合固定的外部契约——协议版本、公共API结构、业务规则)—— 硬编码字面量。该字面量就是契约本身。
- 夹具数据和解析器输入不属于关联测试范畴——保留字面量即可。它们代表被建模的外部场景,而非内部状态。
参数化ID应描述测试场景(如),绝不能包含可变数据值(如)—— 每次依赖版本更新都会变更的ID是不良实践。
attr=min_versionmin_version_is_0.43.0Parametrize ID Hygiene
参数化ID规范
python
undefinedpython
undefinedWRONG — id encodes the data, churns on every bump
错误写法 — ID包含数据,版本更新时会频繁变更
ids=["min_version_is_0.43.0"]
ids=["min_version_is_0.43.0"]
CORRECT — id names the case
正确写法 — ID命名测试场景
ids=["attr=min_version"]
undefinedids=["attr=min_version"]
undefined