try/catch 基础:给代码系安全带
为什么需要错误处理?
想象你开车上路。你不会因为"反正不会出事"就不系安全带吧?代码也一样——有些操作天生就有翻车风险:用户输入了奇怪的东西、网络突然断了、文件找不到了……
不处理错误,程序直接崩溃。处理了错误,程序可以优雅地告诉用户出了什么问题,然后继续干活。
最基本的 try/catch
等等,你发现了吗?JS 那边没有报错!10 / 0 在 JS 里得到 Infinity(无穷大),不会抛出异常。这是一个经典的语言差异——Python 对数学错误很严格,JS 比较"宽容"(或者说"放任")。
Python 的裸 except 是个坑! 上面的例子里 except: 没有指定错误类型,这意味着它会捕获所有错误——包括你按 Ctrl+C 想终止程序时触发的 KeyboardInterrupt。
正确做法是至少写 except Exception:,这样只捕获普通错误,不会拦截系统级异常。
# 不推荐
except:
pass
# 推荐
except Exception as e:
print(f"出错了: {e}")
捕获特定类型的错误
现实中你不会用一张大渔网捞所有东西——你会根据想钓的鱼选择不同的鱼饵。错误处理也一样:
注意关键区别:
| Python | JavaScript | |
|---|---|---|
| 捕获特定错误 | except ValueError: | catch(e) 后用 instanceof 判断 |
| 多种错误类型 | 多个 except 块 | 一个 catch 块 + if/else |
| 获取错误信息 | except ValueError as e: | catch(e) 中 e.message |
Python 的语法更优雅——每种错误一个
except,清清楚楚。JS 只有一个catch,需要自己在里面用instanceof做分类。就像 Python 有多个分拣箱,JS 只有一个大箱子,你得自己翻。
else 和 finally
除了"试着做"和"出错了怎么办",还有两个配角:
| 关键字 | Python | JavaScript | 作用 |
|---|---|---|---|
try | ✅ | ✅ | 尝试执行这段代码 |
except / catch | ✅ | ✅ | 出错时执行 |
else | ✅ | ❌ 没有 | 没出错时执行 |
finally | ✅ | ✅ | 无论如何都执行 |
finally就像老师说的"不管考得好不好,都要交卷"。常用于清理资源——关闭文件、断开连接之类的。
抛出/抛出错误
有时候不是代码自己出错了,而是你发现了一个不对劲的情况,主动"报警":
| Python | JavaScript | |
|---|---|---|
| 抛出错误 | raise ValueError("消息") | throw new RangeError("消息") |
| 关键字 | raise | throw |
| 创建错误对象 | ValueError("消息") | new RangeError("消息") |
raise/throw就像在餐厅吃到头发时喊"服务员!"——你主动把问题抛出来,让上层代码来处理。
问 AI:"什么情况下应该用 try/catch?什么情况下不应该用?我见过有人把整个函数包在 try 里面,这样好吗?"
错误处理不是越多越好。滥用 try/catch 会掩盖真正的 bug,让调试变成噩梦。AI 会告诉你"防御性编程"和"过度防御"之间的界限。
错误处理的实际模式
来看一个更接近真实场景的例子——解析用户输入:
这个模式很常见:尝试做某件事,失败了就用默认值。比如读取配置文件失败就用默认配置,网络请求失败就显示缓存数据。
写一个 safeParse(jsonString) 函数,尝试解析 JSON 字符串:
- 成功返回
{ "ok": True, "data": 解析结果 }(Python)或{ ok: true, data: 解析结果 }(JS) - 失败返回
{ "ok": False, "error": 错误信息 }(Python)或{ ok: false, error: 错误信息 }(JS)
测试这些输入:
'{"name": "Alice"}' → 成功
'not json at all' → 失败
'{"broken": true' → 失败(缺少右大括号)
这种"返回成功/失败对象"的模式在实际开发中非常常见,比直接 try/catch 更容易组合使用。
小结
| 概念 | Python | JavaScript |
|---|---|---|
| 尝试执行 | try: | try { |
| 捕获错误 | except ValueError as e: | catch (e) { |
| 无错执行 | else: | ❌ 没有(写在 try 里) |
| 必定执行 | finally: | finally { |
| 抛出错误 | raise ValueError("消息") | throw new Error("消息") |
| 多类型捕获 | 多个 except 块 | 一个 catch + instanceof |
一句话总结:try/catch 不是用来掩盖错误的,而是用来优雅地处理你预期可能出现的错误。 预期之外的错误?那是 bug,应该修掉,不是 catch 掉。