代码质量
代码质量决定项目的可维护寿命。高质量的代码不仅运行正确,还要易于阅读、易于修改、易于协作。Python 社区通过 PEP 8 风格指南、静态检查工具和类型注解建立了成熟的代码质量保障体系。
PEP 8 与检查工具
PEP 8 是 Python 官方的代码风格指南,涵盖命名约定、缩进、行长度、空行、导入排序等细节。遵守 PEP 8 不是为了形式,而是为了降低团队阅读代码的认知负担。
核心规范包括:
- 缩进使用 4 个空格,不用 Tab。
- 行长度不超过 79 字符(文档字符串/注释不超过 72),现代项目常放宽到 88 或 100。
- 函数和类之间用两个空行分隔,类内方法之间用一个空行。
- 导入按标准库、第三方库、本地模块分组,每组之间空一行。
- 变量用
snake_case,类用CamelCase,常量用UPPER_SNAKE_CASE。
pycodestyle(原 pep8)是专门检查 PEP 8 合规性的工具:
python -m pip install pycodestyle
python -m pycodestyle my_module.py
python -m pycodestyle --max-line-length=88 my_module.py
flake8 是更常用的综合检查工具,它集成了 pyflakes(语法和逻辑错误检查)、pycodestyle(风格检查)和 mccabe(圈复杂度检查):
python -m pip install flake8
python -m flake8 src/
flake8 的输出格式为 文件:行:列 错误码 消息。常见错误码:E501(行过长)、W291(行尾空白)、F401(导入未使用)、F821(未定义名称)。通过 setup.cfg 或 pyproject.toml 可以配置忽略项:
[tool.flake8]
max-line-length = 88
extend-ignore = ["E203", "W503"]
max-complexity = 10
E203(冒号前空格)和 W503(换行符前二元运算符)与 black 格式化工具冲突,通常建议忽略。max-complexity 限制函数圈复杂度,超过 10 意味着函数逻辑过于复杂,应拆分。
类型检查:mypy
Python 是动态类型语言,但 PEP 484 引入了类型注解语法,允许开发者为变量、函数参数和返回值标注类型。mypy 是官方推荐的静态类型检查器,它在不运行代码的情况下分析类型一致性,提前发现类型错误:
from typing import List, Dict, Optional, Callable, Tuple
def get_employees_by_dept(
department: str,
staff_db: Dict[str, List[str]]
) -> List[str]:
"""返回指定部门的所有员工名字。"""
return staff_db.get(department, [])
def find_manager(name: str, chain: Dict[str, str]) -> Optional[str]:
"""查找直属领导,可能不存在。"""
return chain.get(name)
# mypy 会报错:参数类型不匹配
# get_employees_by_dept(123, {}) # error: Argument 1 to "get_employees_by_dept" has incompatible type "int"
Optional[str] 等价于 str | None(Python 3.10+ 写法),表示返回值可能是字符串或 None。mypy 会强制检查调用方是否处理了 None:
manager = find_manager("航仔", {"航仔": "翼王"})
print(manager.upper()) # ❌ mypy 报错:Item "None" of "Optional[str]" has no attribute "upper"
if manager is not None:
print(manager.upper()) # ✅ 通过检查
函数类型和回调注解:
from typing import Callable
# 标注一个接收两个 float 返回 float 的函数
BinaryOp = Callable[[float, float], float]
def apply_op(a: float, b: float, op: BinaryOp) -> float:
return op(a, b)
result = apply_op(3.0, 4.0, lambda x, y: x + y)
运行 mypy src/ 即可对整个项目做类型检查。--strict 模式启用更严格的规则(如要求所有函数都加返回类型、禁止隐式 Any),适合追求高可靠性的项目。
文档字符串规范
文档字符串(docstring)是模块、类、函数/方法内部的第一个字符串字面量,可通过 __doc__ 属性访问,被 help()、pydoc 和 Sphinx 等工具提取生成文档。PEP 257 定义了文档字符串的编写规范:
- 所有公共模块、函数、类、方法都应写文档字符串。
- 首行是简短摘要,以句号结尾,描述对象的作用而非实现细节。
- 如果有多行,第二行空行,第三行开始详细说明。
- 使用三双引号
"""包裹,即使单行也建议用三引号。
Google 风格文档字符串是业界广泛采用的格式,结构清晰,支持工具自动解析:
def calc_tax(salary: float, rate: float = 0.10, deduction: float = 5000.0) -> float:
"""计算个人所得税。
根据工资、税率和起征点计算应缴税额。税额可能为负数,
表示无需缴纳。
Args:
salary: 税前月薪。
rate: 适用税率,默认为 0.10。
deduction: 起征点,默认为 5000.0。
Returns:
计算后的税额(可能为负)。
Raises:
ValueError: 当 salary 为负数时抛出。
Examples:
>>> calc_tax(18888.0)
-3111.2
>>> calc_tax(232000.0)
18200.0
"""
if salary < 0:
raise ValueError("工资不能为负数")
return salary * rate - deduction
NumPy/SciPy 风格则使用 Parameters、Returns、Raises 等节标题,适合科学计算库。无论采用哪种风格,一致性比风格本身更重要:一个项目内应统一使用同一种格式。
pydocstyle 工具可以检查文档字符串是否符合 PEP 257:
python -m pip install pydocstyle
python -m pydocstyle my_module.py
代码审查清单
代码审查(Code Review)是保障质量的关键环节。以下清单覆盖了 Python 项目中最常见的审查要点:
命名与可读性
- 变量名是否准确反映其含义?避免
a、tmp、data1等模糊命名。 - 函数名是否是动词或动词短语?类名是否是名词?
- 魔法数字是否提取为命名常量?
函数与类设计
- 函数长度是否超过 50 行?圈复杂度是否超过 10?
- 函数参数数量是否过多(超过 4 个建议用数据类或字典)?
- 类是否遵循单一职责原则?一个类只做一件事。
异常与边界处理
- 是否捕获了过于宽泛的
except Exception?应捕获具体异常。 - 文件操作、网络请求、数据库连接是否使用了
try/finally或上下文管理器? - 空值(
None、空列表、空字符串)是否被正确处理?
性能与资源
- 大文件读取是否使用迭代器而非一次性读入内存?
- 字符串拼接是否在循环中使用了
+=?应改用str.join()。 - 字典查找是否替代了列表遍历?(
O(1)vsO(n))
测试与类型
- 新增功能是否配套了单元测试?
- 类型注解是否覆盖了公共 API?
mypy和flake8是否全部通过?
安全
- 用户输入是否经过校验?是否防范了 SQL 注入和命令注入?
- 敏感信息(密码、密钥)是否硬编码在源码中?
- 是否使用了
eval()或exec()处理不可信输入?
将上述清单沉淀为项目的 CONTRIBUTING.md 或检查脚本,配合 CI 自动运行 flake8、mypy 和测试套件,可以在代码合并前自动拦截大部分质量问题。