0.9 错误处理与调试
概述
你已经熟悉 JS 的 try/catch/finally、throw、自定义 Error、浏览器的 DevTools 调试器,以及 console.log。Python 的错误处理语法类似但更丰富(多了 else、异常层级更细),调试工具有 pdb,日志有标准库 logging。这一章把错误处理和调试的完整流程对齐。
JS/TS ↔ Python 对照表
核心概念
1. try/except/else/finally vs try/catch/finally
// JS
try {
risky();
} catch (e) {
handle(e);
} finally {
cleanup();
}
# Python
try:
risky()
except SomeError as e:
handle(e)
else:
# 仅当 try 块没有抛出异常时执行(JS 没有)
success()
finally:
cleanup()
catch→except,as e绑定异常对象。Python 多了
else子句:try无异常时执行(常用来放"只有成功才做"的代码,避免被except误捕获)。finally语义完全一致,总是执行。
2. raise vs throw
// JS
if (x < 0) {
throw new Error("x 不能为负");
}
# Python
if x < 0:
raise ValueError("x 不能为负")
throw→raise,且通常抛出特定异常类型(ValueError、TypeError等),比 JS 里清一色Error更精细。
3. 捕获特定异常
try {
JSON.parse(str);
} catch (e) {
if (e instanceof SyntaxError) {
// ...
}
}
try:
import json
json.loads(s)
except json.JSONDecodeError as e:
print("JSON 格式错误")
Python 的异常层级更丰富,鼓励按类型捕获:
try:
value = data["key"] # 可能 KeyError
num = int(value) # 可能 ValueError
except KeyError:
print("键不存在")
except ValueError:
print("值不是数字")
except (TypeError, KeyError) as e: # 捕获多个
print("类型或键错误")
4. 自定义异常类
// JS
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = "ValidationError";
this.field = field;
}
}
# Python
class ValidationError(Exception):
def __init__(self, message, field):
super().__init__(message)
self.field = field
raise ValidationError("字段非法", field="email")
继承
Exception(而非Error,Python 的Error是Exception的子类)。业务错误建议自定义异常,便于上层按类型捕获。
5. 常见异常类型对照
6. pdb 调试器 vs 浏览器 debugger
JS 里你可以在浏览器 DevTools 打断点、单步执行、查看调用栈。Python 的等价物是 pdb(Python Debugger):
// JS:代码里加断点
debugger;
# Python 3.7+:breakpoint() 是内置断点
def buggy(a, b):
breakpoint() # 程序停在这里,进入 pdb 交互
return a / b
pdb 常用命令(类似 DevTools 的按钮):
7. logging vs console
console.log 在 Python 里对应 print,但生产级应用应该用标准库 logging(分级日志):
// JS
console.log("信息");
console.warn("警告");
console.error("错误");
# Python
import logging
logging.basicConfig(level=logging.INFO)
logging.debug("调试信息") # 默认不输出(低于 INFO 级别)
logging.info("信息")
logging.warning("警告")
logging.error("错误")
日志级别从低到高:
DEBUG < INFO < WARNING < ERROR < CRITICAL。可配置输出到文件、控制台、远端,带时间戳、级别、模块名,比
print专业得多。
8. 断言 assert
// JS
console.assert(x > 0, "x 必须为正");
# Python
assert x > 0, "x 必须为正"
assert是 Python 关键字,条件为假时抛AssertionError。注意:
python -O(优化模式)会跳过所有 assert,所以别用 assert 做业务校验,只用于开发期自检。
代码示例
完整的异常处理流程
// JS
function parseConfig(raw) {
try {
const cfg = JSON.parse(raw);
if (!cfg.url) throw new Error("缺少 url");
return cfg;
} catch (e) {
console.error("解析失败:", e.message);
return null;
} finally {
console.log("解析结束");
}
}
# Python
import json
import logging
def parse_config(raw):
try:
cfg = json.loads(raw)
except json.JSONDecodeError as e:
logging.error("JSON 格式错误: %s", e)
return None
except ValueError as e:
logging.error("解析失败: %s", e)
return None
else:
if "url" not in cfg:
raise KeyError("缺少 url")
return cfg
finally:
logging.info("解析结束")
自定义异常 + 特定捕获
// JS
class HttpError extends Error {
constructor(status) { super(`HTTP ${status}`); this.status = status; }
}
try { throw new HttpError(404); } catch (e) {
if (e instanceof HttpError && e.status === 404) { /* ... */ }
}
# Python
class HttpError(Exception):
def __init__(self, status):
super().__init__(f"HTTP {status}")
self.status = status
try:
raise HttpError(404)
except HttpError as e:
if e.status == 404:
...
最佳实践
捕获具体异常类型,别一上来就
except Exception兜底(会掩盖 bug,类似 JS 里吞掉所有异常)。抛出异常用
raise ValueError("明确信息"),选对异常类型,别全用裸Exception。用
else子句放"成功路径"代码,避免把成功逻辑写进try又没异常时被误捕获。生产日志用
logging(分级、可配置),别用print。调试用
breakpoint()(Python 3.7+),它比pdb.set_trace()更简洁且可被环境变量关闭。assert只用于开发期自检,不用于运行时校验(-O会跳过)。给外部数据(API、文件)做校验,考虑用 pydantic,而不是满屏 try/except。
前端开发者常见陷阱
写
catch而非except:try/except,不是try/catch,写错直接SyntaxError。except Exception吞掉一切:包含KeyboardInterrupt(Ctrl+C 也能被吞)等系统异常,正确的兜底是except Exception,裸except:会连系统退出都吞。重新抛出用
raise而非raise e:raise(不带参数)保留原始堆栈,raise e会重置 traceback,调试更难。else和finally顺序:顺序是try → except → else → finally,写反报错。用
assert做参数校验:-O模式会跳过 assert,导致校验失效。异常对象没有
.message:Python 用str(e),堆栈要import traceback; traceback.format_exc()。KeyErrorvsAttributeError搞混:字典缺键是KeyError,对象缺属性是AttributeError,别混用。把
console.error当logging.error:Python 的 logging 需要先basicConfig配置,否则默认可能不输出到控制台(级别默认 WARNING)。finally里 return 覆盖异常:finally中return会吞掉原异常/返回值(JS 也同理),避免在 finally 里 return。忽略
breakpoint()的调用栈:pdb 交互式命令和 DevTools 按钮不同,先学n/s/c/p四个命令就够用。
总结
try/except/else/finally对应try/catch/finally,except代替catch,多了else。throw→raise,自定义异常继承Exception,异常层级比 JS 更细。Python 用
breakpoint()+ pdb 调试(对应debugger+ DevTools)。生产日志用
logging(分级),替代console.log;assert仅用于开发自检。按异常类型捕获、用
raise重抛保留堆栈、避免except Exception兜底,是 Python 错误处理的核心原则。
0.9-错误处理与调试
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法