开发者警告:别为通过类型检查把运行时错误改成静默bug
来源标题:Don't let type checkers push you to convert loud runtime errors to silent bugs
有开发者撰文指出,为通过类型检查器而放宽函数签名(如允许None并返回None),会把原本显眼的运行时错误变成静默bug。文中以Python加法函数为例:类型检查报int|None不匹配后,开发者若改成允许None并返回None,数据就可能以None写入数据库。作者认为这并非类型安全的胜利,应在更早的环节处理类型问题。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
别让类型检查器逼你把显眼的运行时错误变成无声的 bug
你刚写完(或别人替你写完)一个函数,它做一次计算并把结果保存到数据库: def calculation(a: int, b: int) -> int: return a + b result = calculation(data_a, data_b) save_result_to_database(result) 作为一个勤勉的 Python 开发者,你对它跑了一遍类型检查器。结果报错: error: Argument 1 to "calculation" has incompatible type "int | None"; expected "int" error: Argument 2 to "calculation" has incompatible type "int | None"; expected "int 于是你改了这个函数,让类型检查器通过: def calculation(a: int | None, b: int | None) -> int | None: if a is None or b is None: return None return a + b result = calculation(data_a, data_b) save_result_to_database(result) 这也许是正确的做法。你也许确实想把那个 None 值存进数据库。但根据我的经验,更常见的情况是:你刚刚做的,其实是把本该显眼的运行时错误变成了无声的 bug。 这算不上类型安全的胜利。 所以在上面的例子里,应该往处理流程的更早处(也许要往前找很远)去看,而不是盯着类型检查器报错的位置,在那里处理 None 的情况。 if data_a is None or data_b is None: raise ValueError() def calculation(a: int, b: int) -> int: return a + b result = calculation(data_a, data_b) save_result_to_database(result) 现在你有了一个定义明确的校验阶段:数据不符合预期时就显式报错;你避免了把坏数据写进数据库;你仍然保留了一个不处理 None 的清晰核心函数;而且类型检查器也满意了 🏆。 在这个例子里,类型检查器之所以能通过,是因为它能理解针对 None 的检查;但在更复杂的情况下,TypeGuard 是个很好的工具,它让你可以引入运行时检查,并把检查结果传达给类型检查器。 总结一下:类型安全是个很好的工具,但不加思考地去迎合类型检查器,不仅浪费时间(或 token 😜),如果方式不对,还会让你的系统变得更糟。
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。