第2章 注释的重要性:为什么需要注释,注释的类型
这一章我们聊聊注释。你可能觉得注释是“写了反正也没人看”的东西。说实话,我刚入行时也这么想。后来在一个维护了三年的项目里,我被一段没有注释的代码坑了整整两天——那段代码的作者早就离职了,逻辑还特别绕。从那以后,我养成了“先把注释补齐再下手改”的习惯。
注释不是写给编译器看的,是写给未来的你和其他开发者看的。说白了,注释就是代码的“使用说明书”。
为什么需要注释
先列几个我在项目中反复碰到的场景,你就明白了。
- 解释意图:代码能告诉你“做了什么”,但不一定告诉你“为什么这么做”。比如一个奇怪的排序顺序,如果没有注释,后来的人可能直接改成“标准”顺序,结果破坏了业务逻辑。
- 备忘与提醒:有些临时代码、待办事项、已知缺陷,需要明确标注。我习惯用
TODO和FIXME做标记,方便搜索。 - API 使用指引:函数参数的单位、返回值范围、异常情况,光靠类型声明不够。好的文档字符串能省大量 debug 时间。
- 自动化检查辅助:后面章节会讲,有些注释(比如
# noqa、# type: ignore)能配合工具跳过误报,保证检查流程顺畅。
核心原则:注释应该解释“为什么”,而不是“是什么”。i += 1 # 计数器加1 这种废话注释还不如不写。
我的小经验:每次写完一段逻辑,花10秒问自己“如果半年后的我看到这段代码,会不会需要解释?”如果需要,就加注释。别以为自己能记住,你记不住的。
注释的类型
Python 里注释分三种:行注释、块注释、文档字符串。很多人混着用,但各有各的场合。下面这个表格帮你快速区分。
| 类型 | 语法 | 主要用途 | 是否被解释器读取 | 常见场景 |
|---|---|---|---|---|
| 行注释 | # 注释内容 |
解释单行代码的意图或临时禁用 | 否(编译时忽略) | 复杂算法的一行说明、调试时注释掉某行 |
| 块注释 | 连续多行 # |
解释一段代码的逻辑、背景或注意事项 | 否 | 函数内部较长逻辑的分段说明、版权信息 |
| 文档字符串 | """ 文本 """ 或 ''' 文本 ''' |
模块、类、函数的正式说明,可供工具提取 | 是(作为 __doc__ 属性存储) |
生成 API 文档、IDE 智能提示、单元测试用例说明 |
行注释
行注释以 # 开头,整行有效,或者放在代码行末尾。我常用的场景是解释“为什么选了这个值”或者临时测试。
max_retry = 3 # 服务端平均响应时间200ms,重试3次约能覆盖99%的临时故障
注意:行注释不要和代码挤在一起,# 前至少留两个空格,保持可读性。
块注释
当需要解释一段复杂逻辑,一行写不下时,用连续多行 # 组成块注释。我自己习惯在块注释前加一个空行,避免和代码粘连。
# 这里使用了双指针法,左指针从0开始,右指针从末尾开始
# 每次比较两个指针对应的值,如果相等则同时移动
# 否则根据大小关系移动其中一个指针,目的是找到最长回文子串
while left < right:
if s[left] == s[right]:
left += 1
right -= 1
else:
# 不相等时,尝试跳过左或右字符,记录最大长度
...
曾踩过的坑:我在一个项目里看到有人用块注释写了一大段中文,但代码改了之后注释忘了更新。结果新同事按注释理解逻辑,改了三天发现不对。记住——注释是活的,代码改完立刻更新注释,比补一个“TODO”更靠谱。
文档字符串
文档字符串是 Python 最优雅的注释形式。它被解释器保存为对象的 __doc__ 属性,能被 help()、IDE 和文档生成工具(如 Sphinx)读取。你需要把它写在模块、类、函数、方法的定义体开头。
def calculate_confidence(score: float, sample_size: int) -> float:
"""
根据样本评分和样本量计算置信度。
参数
----------
score : float
模型评分,范围 [0.0, 1.0]
sample_size : int
样本数量,必须大于0
返回
-------
float
调整后的置信度,范围 [0.0, 1.0]
示例
--------
>>> calculate_confidence(0.9, 100)
0.89
"""
if sample_size <= 0:
raise ValueError("sample_size must be positive")
return score * (1 - 1 / (sample_size + 10))
我建议团队统一文档字符串的格式,比如 Google 风格或 NumPy 风格。后面讲到自动化检查时,这些格式能直接配合工具验证参数类型、异常信息是否和代码一致。
知识结构图
下面这张 SVG 图总结了注释的类型、作用以及它们和代码检查工具的关系。你可以把它当作本章的思维导图。
避坑指南
结合我自己的经验,有三个常见的注释陷阱,你一定要注意。
- 不要用注释代替版本控制——有人在文件头写
# 修改人: 张三 2023-01-01,然后每次改代码都改这个注释。其实 Git log 比注释更准确。这种“人肉版本库”只会误导人。 - 文档字符串别偷懒少写参数——如果函数签名改了,但文档字符串没更新,工具检查时会报“参数不匹配”。我见过一个线上事故,就是因为文档里写“参数a是整数”,实际代码接收了字符串,调用方按文档传入整数导致类型错误。
- 行注释别滥用“魔法数字”——比如
timeout = 30 # 等待30秒这种注释基本是多余。更好的做法是用常量命名WAIT_TIMEOUT_SECONDS = 30,让代码自己说话。注释应该解释“为什么是30”,而不是“30是什么”。
一个小技巧:写代码时可以先写文档字符串,再写函数体。这叫“文档驱动开发”,能帮你理清输入输出,减少返工。而且后续一致性检查工具可以直接拿文档字符串和签名对照,提前发现不一致。