Python 报错别整段丢给 AI:用最小复现定位 KeyError Python 报错别整段丢给 AI用最小复现定位 KeyError摘要遇到 KeyError把整段日志交给 AI未必能得到正确修复。用一个可运行的 Python 示例演示如何整理最小复现、补充业务规则、约束修改范围并通过 10 个检查验证结果。附可直接复制的排错提示词。接口返回了用户数据页面却在读取城市时崩了。报错只有一句KeyError: profile。把它发给 AI可能得到一条看上去很省事的建议把方括号取值改成.get()。代码不再报同一个错但缺失数据应该显示“未知”还是应该阻止后续处理这个决定异常信息里没有。排错时值得先整理的是什么输入触发了错误以及这个输入按业务要求应该得到什么结果。以下是为讲解构造的用户资料示例不涉及真实用户数据。代码仅使用 Python 标准能力无第三方依赖建议在 Python 3.10 或更高版本中练习。1. 先把问题缩小到能独立运行假设原项目包含请求接口、读取缓存、解析数据和渲染页面。当前已经拿到触发异常的返回值就可以先把网络请求移除只保留数据和取值语句。保存为repro.pyuser{id:demo-001}cityuser[profile][city]print(city)运行python repro.py异常末行应为KeyError: profilePython 官方文档说明KeyError表示映射中找不到指定的键。这里第一次访问user[profile]就失败了程序还没有读取city。参见 Python 官方异常说明。最小复现的价值是让“接口可能有问题”变成一个具体事实当前字典没有profile代码却直接读取它。至于上游为什么没返回这个字段仍然需要检查接口约定和实际响应不能仅凭这三行代码下结论。如果删除网络、并发或缓存之后错误消失就说明它们可能是触发条件需要逐步加回来。最小复现必须保留原问题不能为了代码短而改变问题。2. 先确定缺失值应该怎么处理对这个展示城市名称的示例先约定以下规则输入情况预期行为profile.city是非空字符串去掉首尾空格后返回没有profile或没有city返回“未知”profile存在但不是字典抛出ValueErrorcity存在但不是字符串或只有空白抛出ValueError用户数据本身不是字典抛出ValueError这里有一个容易被忽略的区分没有提供字段和提供了格式错误的字段是两种情况。这些规则是示例的业务选择不是所有项目都应该照搬的标准。例如某个必填字段缺失时业务也可能要求直接拒绝处理。把规则写出来AI 才知道哪些输入允许降级哪些输入必须暴露错误。3. 把“帮我修一下”换成可验证的请求可以把下面的提示词和最小复现代码一起提交给你正在使用的 AI 编程助手。运行环境应填写自己的实际版本用python --version即可查看。请协助定位以下 Python 错误。 环境填写实际 Python 版本与操作系统。 任务从用户字典中读取 profile.city用于页面展示。 实际结果KeyError: profile。 最小复现 user {id: demo-001} city user[profile][city] 业务规则 1. 缺少 profile 或 city 时返回“未知”。 2. profile 存在时必须是字典。 3. city 存在时必须是非空字符串返回前去除首尾空格。 4. 类型错误、空字符串或纯空白字符串应抛出 ValueError。 5. user 本身不是字典时也抛出 ValueError。 请按以下顺序回答 - 区分已确认的事实与仍需验证的猜测。 - 指出具体失败表达式及原因。 - 给出一个 get_city(user) 函数只解决上述问题。 - 给出正常、字段缺失、字段非法的可运行验证代码。 约束不用第三方依赖不重构其他模块不用宽泛的 except Exception 把所有错误统一转成“未知”。 如果证据不足请指出需要补充什么不要编造上游原因。真实项目里还应附上脱敏后的异常堆栈和相关调用代码。保留错误类型、调用顺序、字段名与数据类型替换令牌、账号标识等敏感值。没有必要为了说明一个取值错误上传整份生产日志。4. 检查修改是否符合规则下面是按上述约定编写的参考实现并非某次 AI 对话的实测输出。保存为example.pydefget_city(user):ifnotisinstance(user,dict):raiseValueError(user must be a dict)ifprofilenotinuser:return未知profileuser[profile]ifnotisinstance(profile,dict):raiseValueError(profile must be a dict)ifcitynotinprofile:return未知cityprofile[city]ifnotisinstance(city,str)ornotcity.strip():raiseValueError(city must be a non-empty string)returncity.strip()为什么不直接写成这样cityuser.get(profile,{}).get(city,未知)因为.get()的默认值只在键不存在时生效。如果profile存在但值是None后续调用.get()仍然会失败如果city是None上面这行则会返回None不会自动替换成“未知”。具体语义可查 Python 官方字典方法说明。另一种写法也需要小心city(user.get(profile)or{}).get(city)or未知它把部分假值一起折叠成了默认结果。例如空列表形式的profile、数值为0的city都可能被隐藏成“未知”违反前面约定的类型校验规则。代码行数可以少但不能把业务上需要区分的状态合并掉。5. 用输入和断言验收结果把下面内容追加到example.py后运行。前四个检查验证返回值后六个检查验证非法数据确实被拒绝if__name____main__:cases[({profile:{city:杭州}},杭州),({},未知),({profile:{}},未知),({profile:{city: 杭州 }},杭州),]fordata,expectedincases:assertget_city(data)expected invalid[None,{profile:None},{profile:[]},{profile:{city:None}},{profile:{city: }},{profile:{city:0}},]fordataininvalid:try:get_city(data)exceptValueError:passelse:raiseAssertionError(fExpected ValueError:{data!r})print(10 checks passed)python example.py本次交付已在本地 Python 环境执行上述验证输出为10 checks passed使用普通模式运行不要加-O因为优化模式会移除assert。这些检查只覆盖示例约定没有验证真实接口、页面或线上环境。接回项目后还需要确认“未知”的展示方式以及ValueError是否被调用方正确处理。如果验证失败把失败输入、预期结果、实际结果重新交给 AI比一句“还是不行”更有用。一次只处理一个可复现问题也更容易看清修改是否引入了新行为。6. 下次排错先准备这张问题卡任务这段代码本来要完成什么 环境语言版本、相关依赖版本、操作系统。 复现最小输入、最短代码、执行命令。 证据脱敏堆栈、实际输出、已排除的原因。 规则正确结果是什么哪些输入必须拒绝 验收哪些用例通过后才算修好AI 可以帮助解释堆栈、提出排查方向和补充边界用例是否修好最终要靠你的业务规则和运行结果判断。