0%

异常处理

Python 异常处理详解(Python 3.x)

异常处理是编程中应对错误的重要机制,Python 提供了灵活的异常处理语法,通过 tryexceptelsefinally 等关键字实现对错误的捕获、处理和资源清理。本文将详细介绍 Python 异常处理的基本用法、手动抛异常及常见场景。

基本异常处理结构

Python 异常处理的核心语法是 try...except,用于捕获并处理程序运行中可能出现的错误。

基础结构:try...except

1
2
3
4
5
6
try:
# 可能发生异常的代码块
result = 1 / 0 # 除数为 0,会触发 ZeroDivisionError
except ZeroDivisionError as e:
# 捕获特定异常并处理
print(f"发生错误:{e}") # 输出:发生错误:division by zero

说明

  • try 块:包含可能触发异常的代码。
  • except 块:指定要捕获的异常类型,as e 用于获取异常对象(包含错误信息)。
  • try 块中无异常,except 块不执行;若发生指定类型的异常,跳至 except 块处理。

捕获多种异常

可使用多个 except 块处理不同类型的异常,或在一个 except 中捕获多个异常:

1
2
3
4
5
6
7
8
9
10
try:
num = int(input("请输入一个整数:"))
result = 10 / num
except ValueError:
print("输入错误:请输入有效的整数")
except ZeroDivisionError:
print("计算错误:除数不能为 0")
except (TypeError, OverflowError):
# 同时捕获多种异常(用元组包裹)
print("其他类型错误")

执行逻辑

  • 程序按顺序检查 except 块,匹配到第一个对应异常类型后执行,不再检查后续块。
  • 建议先捕获具体异常(如 ValueError),再捕获通用异常(如 Exception),避免覆盖特定异常。

捕获所有异常(不推荐)

使用 except Exception 可捕获所有非系统退出的异常(不包括 KeyboardInterrupt 等):

1
2
3
4
5
6
try:
# 任意可能出错的代码
lst = [1, 2, 3]
print(lst[10]) # 索引越界,触发 IndexError
except Exception as e:
print(f"发生未知错误:{e}") # 输出:发生未知错误:list index out of range

注意:过度使用通用异常捕获可能隐藏代码逻辑错误,建议仅在需要统一处理所有异常的场景使用(如日志记录)。

else 子句:无异常时执行

else 子句可选,用于定义当 try 块中无异常时执行的代码:

1
2
3
4
5
6
7
8
9
try:
num = int(input("请输入一个正数:"))
if num <= 0:
raise ValueError("必须输入正数") # 手动抛异常(见下文)
except ValueError as e:
print(f"错误:{e}")
else:
# 无异常时执行
print(f"你输入的正数是:{num}")

示例执行

  • 若输入 5(无异常):输出 你输入的正数是:5
  • 若输入 -3(触发异常):输出 错误:必须输入正数

finally 子句:必执行的清理操作

finally 子句用于定义无论是否发生异常都必须执行的代码,通常用于释放资源(如关闭文件、网络连接):

1
2
3
4
5
6
7
8
9
10
11
12
file = None
try:
file = open("data.txt", "r")
content = file.read()
print("文件内容:", content)
except FileNotFoundError:
print("错误:文件不存在")
finally:
# 无论是否发生异常,都关闭文件
if file is not None:
file.close()
print("文件已关闭")

说明

  • 即使 tryexcept 块中包含 returnfinally 仍会执行。
  • 常用于资源清理,确保资源不会因异常而未释放。

手动抛出异常(raise

使用 raise 关键字可手动触发异常,用于在满足特定条件时主动报错(如参数校验)。

基本用法

1
2
3
4
5
6
7
8
9
10
def check_age(age):
if age < 0:
# 手动抛出 ValueError 异常
raise ValueError(f"年龄不能为负数:{age}")
print(f"年龄是:{age}")

try:
check_age(-5)
except ValueError as e:
print(f"捕获到错误:{e}") # 输出:捕获到错误:年龄不能为负数:-5

抛出自定义异常

除了 Python 内置异常(如 ValueErrorTypeError),还可定义自定义异常类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定义自定义异常(继承自 Exception)
class InvalidScoreError(Exception):
"""分数无效异常(分数必须在 0-100 之间)"""
pass

def check_score(score):
if not (0 <= score <= 100):
# 抛出自定义异常
raise InvalidScoreError(f"无效分数:{score}(必须在 0-100 之间)")

try:
check_score(150)
except InvalidScoreError as e:
print(f"错误:{e}") # 输出:错误:无效分数:150(必须在 0-100 之间)

自定义异常优势:使异常类型更贴合业务逻辑,便于精准捕获和处理。

常见内置异常类型

Python 提供了多种内置异常,以下是常用类型:

异常类型 说明 示例场景
ValueError 值无效 int("abc")(字符串无法转整数)
TypeError 类型错误 "2" + 3(字符串与整数相加)
IndexError 序列索引越界 [1,2][5](列表索引超出范围)
KeyError 字典键不存在 {"a":1}["b"](访问不存在的键)
FileNotFoundError 文件不存在(打开文件时) open("nonexist.txt")
ZeroDivisionError 除数为 0 1 / 0
AttributeError 对象属性不存在 [].nonexist_method()

异常处理最佳实践

  1. 捕获具体异常:避免使用 except Exception 捕获所有异常,应针对性捕获可能发生的异常(如 FileNotFoundError)。
  2. 提供有用的错误信息:在异常处理中说明错误原因,便于调试(如 print(f"文件 {filename} 不存在"))。
  3. 使用 finally 释放资源:文件、网络连接等资源必须在 finally 中关闭,防止资源泄露。
  4. 合理使用自定义异常:对于业务特定的错误(如 “分数超出范围”),定义自定义异常可提高代码可读性。
  5. 避免过度使用异常:异常处理开销较高,可通过条件判断避免的错误(如检查除数是否为 0),无需依赖异常。

欢迎关注我的其它发布渠道