第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 图总结了注释的类型、作用以及它们和代码检查工具的关系。你可以把它当作本章的思维导图。

注释类型与作用概览 注释类型与作用概览 注释 行注释 # 块注释 # ... # 文档字符串 """ 解释单行 / 临时禁用 解释一段逻辑 / 背景 API说明 / 工具提取 注释一致性检查工具(如 pydocstyle, flake8-docstrings)可自动验证文档字符串格式

避坑指南

结合我自己的经验,有三个常见的注释陷阱,你一定要注意。

  1. 不要用注释代替版本控制——有人在文件头写 # 修改人: 张三 2023-01-01,然后每次改代码都改这个注释。其实 Git log 比注释更准确。这种“人肉版本库”只会误导人。
  2. 文档字符串别偷懒少写参数——如果函数签名改了,但文档字符串没更新,工具检查时会报“参数不匹配”。我见过一个线上事故,就是因为文档里写“参数a是整数”,实际代码接收了字符串,调用方按文档传入整数导致类型错误。
  3. 行注释别滥用“魔法数字”——比如 timeout = 30 # 等待30秒 这种注释基本是多余。更好的做法是用常量命名 WAIT_TIMEOUT_SECONDS = 30,让代码自己说话。注释应该解释“为什么是30”,而不是“30是什么”。

一个小技巧:写代码时可以先写文档字符串,再写函数体。这叫“文档驱动开发”,能帮你理清输入输出,减少返工。而且后续一致性检查工具可以直接拿文档字符串和签名对照,提前发现不一致。