Kodokon kodokon.com

错误与异常:try、except、raise

用 try/except/else/finally 捕获可预见的失败,并抛出你自己的异常来标示无效数据。

9 分钟 · 3 题

在 Kodokon 中打开本课

真实的程序总会失败:文件缺失、输入无效、网络中断。Python 用异常来标示这些情况:异常会中断执行,并沿着调用栈向上传播,直到某个 try/except 捕获它。专业的反应是:捕获尽可能具体的异常,并且尽可能靠近你知道该怎么处理的地方。

PYTHON
def parse_age(text):
    try:
        return int(text)
    except ValueError:
        return None

print(parse_age("34"))      # 34
print(parse_age("thirty"))  # None
我们精确地捕获 ValueError,而不是捕获所有错误。

完整的结构有四个分支。try 包含有风险的代码,except 处理失败,else 仅在没有异常被抛出时运行,而 finally 在任何情况下都会运行 - 非常适合释放资源或记录日志。else 的意义在于:让 try 保持最小,这样你一眼就能看出哪一行可能出错。

PYTHON
values = ["10", "abc", "25"]
total = 0

for value in values:
    try:
        number = int(value)
    except ValueError:
        print(f"Skip : {value}")
    else:
        total += number
    finally:
        print(f"Process : {value}")

print(total)  # 35
else 只在没有错误时运行;finally 则总是运行。

只要收到的某个数据无效,你的函数也可以用 raise 抛出自己的异常:带着清晰的消息立刻失败,好过产出一个错误的结果。请定义一个继承自 Exception 的专用类:这样调用方就能有针对性地捕获它,而不会误伤其他错误。

PYTHON
class EmptyCartError(Exception):
    pass

def checkout(items):
    if not items:
        raise EmptyCartError("Empty cart.")
    return round(sum(items), 2)

try:
    print(checkout([]))
except EmptyCartError as error:
    print(f"Error : {error}")
一个专用的业务异常让失败变得明确而有针对性。

知识检测

确认你已牢记本课的重点内容。

  1. try/except 的 else 代码块什么时候运行?
    • 仅当 try 中没有抛出任何异常时
    • 仅当有异常被捕获时
    • 任何情况下都运行,就在 try 之后
  2. finally 代码块在哪些情况下运行?
    • 仅当有异常被抛出时
    • 仅当没有异常被抛出时
    • 任何情况下都运行,无论有没有异常
  3. 为什么要避免使用捕获一切的裸露 except:?
    • 它会掩盖真正的 bug,让调试变得极其困难
    • 它比有针对性的 except 更慢
    • 它只对标准库中的异常有效