注释和代码逻辑对不上,通常不是模型读不懂这段代码,而是提示里给出的上下文和你要求它解释的范围不匹配:只贴函数体,模型只能靠命名去猜参数含义;把调用方和类型定义一起贴进去,参数含义和副作用这两类偏差往往先被消掉。可操作的做法是:先把偏差分类,再用同一个函数按“仅函数体 / 函数加调用方 / 再加类型与样例”三种范围各生成一次注释,对照哪一类偏差被修正,最后把验证有效的范围写进项目注释规范,而不是每次提示时临时想。
处理这类问题,先把“注释不对”拆成参数含义、返回值条件、副作用、异常说明四类偏差;再对同一函数按三种上下文范围各生成一次,比较每类偏差是否被消掉。通常函数加调用方足以纠正参数含义与副作用类偏差,类型定义和数据样例主要补返回值条件与边界取值。有效范围应固化成“必贴 / 可贴 / 禁止贴”条目。模型输出一律当草稿,合并前逐句对照实现,冲突处一律以代码行为为准。
挑一条对不上的注释,标出它错在哪一类
判断方法很直接:把注释里的每一句话拿去代码里找依据,找不到对应语句的句子就是偏差。与其说“注释写得不对”,不如把它归到下面四类里,后面才谈得上用上下文去修。
- 参数含义:这个参数在调用处实际传的是什么?是否与名字字面意思一致?
- 返回值条件:什么情况下返回什么?空值、异常、部分字段缺失各走哪条分支?
- 副作用:函数体内是否写库、写缓存、写日志、改入参?注释有没有提?
- 异常说明:哪些错误是本函数返回的,哪些是往上抛的?
下面这段是刻意保留的错误注释,用来示范分类,不要直接抄进代码:
def fetch_user(uid, include_deleted=False):
# 模型生成的注释:按用户名查询用户;用户不存在时抛 KeyError;
# include_deleted=True 时只返回已删除用户。
row = db.query_one("select * from users where id = %s", uid)
if row is None:
return None
if row["deleted"] and not include_deleted:
return None
return dict(row)
按四类拆开就是:uid 是主键而不是用户名(参数含义);不存在时返回 None 而不是抛 KeyError,已删除且未显式包含时也返回 None(返回值条件);这个函数没有写操作,若实际版本里有缓存写入而注释没写,那就是副作用漏写;数据库连接错误会向上抛,注释若写“不会抛异常”属于异常说明错误。分类做完,你才有明确的对照目标。
检查提问时贴进去的代码范围
先确认当时到底贴了什么,而不是凭印象判断“给得不够”。三种范围可以这样定义:
- 仅函数体:只有这一个函数的定义,没有别的东西。
- 函数加调用方:函数定义,加上至少一处真实调用点,能看到实参怎么传。
- 类型加样例:在上一档基础上,再附上返回值结构、模型或 schema 定义,以及一两条脱敏后的输入样例。
多数编辑器和对话记录会保留你上一次的粘贴内容,翻一下就能对上号;如果记录已经丢了,就按同一提示重做一次,把范围写清楚。下面是一个可复用的提示骨架,把方括号里的内容替换成你的实际代码:
任务:为下面的函数补一段说明注释,只输出注释与函数体
上下文范围:[仅函数体 / 函数 + 一处调用方 / 函数 + 调用方 + 类型定义 + 输入样例]
要求:
- 参数含义必须能从签名、调用方或样例中推出,推不出就写“不确定”
- 返回值条件按分支逐条写,不要合并成一句
- 有写库、写缓存、写日志、改入参的,逐条列出
- 不要补写代码里不存在的异常处理
这一步的作用是把变量控制在“上下文范围”上,其他条件都保持不变,否则三份结果没法比较。
按三种范围各生成一次,对比注释准确度变化
同一个函数、同一套要求,只改上下文范围,各生成一份,把结果并排贴在同一个文件或同一个提交里逐句对照。下表是常见的对照结果,具体到你自己的函数需要以实际生成为准:
| 偏差类型 | 仅函数体 | 函数 + 调用方 | 再加类型与样例 |
|---|---|---|---|
| 参数含义 | 容易按名字猜,偏得多 | 通常能靠实参纠正 | 基本不再改口 |
| 返回值条件 | 常把分支合并成一句 | 改善有限 | 多半能逐条写出 |
| 副作用 | 函数体内可见的能写对 | 调用方的顺序依赖会暴露出来 | 变化不大 |
| 异常说明 | 常见“不会抛异常”之类臆断 | 变化不明显 | 能对照类型定义收紧表述 |
记录方式建议固定下来:三次输出分别存成 comment_v1.txt、comment_v2.txt、comment_v3.txt,然后逐句和实现比对,标出每一句的依据在哪一行。想快速验证某个参数在调用处的真实用法,可以在仓库里搜一遍:
grep -rn "include_deleted" `--include`=*.py src/ | head -20
如果“函数加调用方”这一档已经能把参数含义和副作用类偏差消掉,而返回值条件仍然含混,那说明缺的是类型和数据样例,不必再把整个模块贴进去。
把有效范围写成固定模板放进注释规范
把上一步验证有效的范围固化成条目,后面补注释的人按同一标准提交,就不用每次重新试。可以直接把下面这段放进仓库的 CONTRIBUTING 或注释规范文档:
补注释时的上下文提交规范
必贴内容:
- 目标函数的完整定义(含装饰器、默认参数)
- 至少一处直接调用方
- 返回值涉及的结构定义或查询字段清单
可贴内容:
- 一到两条脱敏后的真实输入样例
- 错误分支的返回约定(谁负责兜底)
- 上游约束说明,如取值范围、单位
禁止贴内容:
- 与本函数无关的模块或整份配置文件
- 密钥、令牌、真实用户数据
- 超出本函数职责的设计讨论、待办清单
条目要能被执行:在代码评审时,如果注释涉及参数含义或副作用,就要求提交者说明调用方来自哪里;涉及返回值条件,就要求指向类型定义或数据样例。边界上留一句“需要结合具体语言和框架确认”,不要把它当成跨语言通用规则硬套。
合并前逐条复核注释
模型给的注释按草稿处理,合并前逐句对照实现确认,处理顺序建议固定成下面几步:
- 每个参数在签名、调用方或样例中找到至少一处依据,找不到就删掉这句描述。
- 返回值按代码分支逐条核对,注释里出现代码中不存在的分支,直接删除。
- 副作用逐句指向函数体内的具体语句,如写库、写缓存、写日志、修改入参。
- 异常说明区分“本函数返回的错误值”和“向上抛出的异常”,以实际 raise 或错误返回路径为准。
处置规则保持简单:注释与代码行为冲突时,默认改注释;如果确认代码本身是缺陷(例如本该返回 None 却抛异常),那就另开一个修复项,不要用改注释的方式把问题掩盖过去。复核人如果对某句注释有异议,以代码运行时的实际行为为准,而不是以注释看起来是否通顺为准。
验证手段不需要额外工具:用 grep 搜参数名确认调用方式,用单元测试或交互式调用跑一遍边界输入确认返回值,用日志观察是否有写操作被触发。这几步做完,注释和代码逻辑才能真正对上,而不是看着通顺。