本文目录导读:

我来用实际案例详细说明Python异常的分类和处理方法。
异常分类概览
# 异常体系结构
BaseException
├── SystemExit # 解释器退出
├── KeyboardInterrupt # 用户中断(Ctrl+C)
├── GeneratorExit # 生成器退出
└── Exception # 大多数异常基类
├── AttributeError # 属性错误
├── IOError # I/O错误
├── ImportError # 导入错误
├── IndexError # 索引错误
├── KeyError # 键错误
├── NameError # 名称错误
├── TypeError # 类型错误
├── ValueError # 值错误
├── ZeroDivisionError # 除零错误
└── ...
常见异常区分案例
# 案例1:不同类型异常对比
def exception_comparison():
# 1. IndexError vs KeyError
my_list = [1, 2, 3]
my_dict = {'a': 1, 'b': 2}
try:
print(my_list[5]) # IndexError: list index out of range
except IndexError:
print("索引越界错误!")
try:
print(my_dict['c']) # KeyError: 'c'
except KeyError:
print("键不存在错误!")
# 2. ValueError vs TypeError
try:
int("abc") # ValueError: invalid literal
except ValueError:
print("值转换错误!")
try:
"123" + 456 # TypeError: can only concatenate str (not "int") to str
except TypeError:
print("类型不匹配错误!")
# 3. AttributeError vs NameError
try:
my_list.appendd(4) # AttributeError: 'list' object has no attribute 'appendd'
except AttributeError:
print("属性不存在错误!")
try:
print(undefined_var) # NameError: name 'undefined_var' is not defined
except NameError:
print("变量未定义错误!")
exception_comparison()
实际业务场景异常处理
class DataProcessor:
"""数据处理类,展示各种异常处理"""
def process_user_data(self, user_data):
"""
处理用户数据的完整异常处理示例
"""
try:
# 1. 检查数据类型
if not isinstance(user_data, dict):
raise TypeError(f"期望dict类型,收到{type(user_data)}")
# 2. 检查必要字段
required_fields = ['name', 'age', 'email']
for field in required_fields:
if field not in user_data:
raise KeyError(f"缺少必要字段: {field}")
# 3. 数据验证
name = user_data['name']
if not isinstance(name, str) or len(name) == 0:
raise ValueError("姓名必须是非空字符串")
age = user_data['age']
if not isinstance(age, int) or age < 0 or age > 150:
raise ValueError(f"年龄不合法: {age}")
# 4. 处理业务逻辑
result = self._calculate_score(age)
# 5. 文件操作可能出错
with open(f"user_{name}.txt", 'w') as f:
f.write(str(result))
return result
except TypeError as e:
print(f"类型错误: {e}")
return None
except KeyError as e:
print(f"键错误: {e}")
return None
except ValueError as e:
print(f"值错误: {e}")
return None
except IOError as e:
print(f"文件I/O错误: {e}")
return None
except Exception as e:
print(f"未知错误: {type(e).__name__}: {e}")
return None
def _calculate_score(self, age):
"""计算分数(可能抛出除零错误)"""
try:
return 100 / (age - 30) # 当age=30时触发ZeroDivisionError
except ZeroDivisionError:
print("警告:年龄恰好为30,使用默认值")
return 0
# 使用示例
processor = DataProcessor()
# 测试各种异常情况
test_cases = [
"not a dict", # TypeError
{"name": "Alice"}, # KeyError (缺少age和email)
{"name": "", "age": 25, "email": "a@b.com"}, # ValueError (空姓名)
{"name": "Bob", "age": 200, "email": "b@c.com"}, # ValueError (年龄过大)
{"name": "Charlie", "age": 30, "email": "c@d.com"}, # ZeroDivisionError
{"name": "David", "age": 25, "email": "d@e.com"}, # 正常情况
]
for i, test_data in enumerate(test_cases, 1):
print(f"\n测试用例 {i}:")
result = processor.process_user_data(test_data)
print(f"处理结果: {result}")
自定义异常类(专业做法)
class CustomBusinessError(Exception):
"""自定义业务异常基类"""
pass
class ValidationError(CustomBusinessError):
"""数据验证错误"""
def __init__(self, field, message):
self.field = field
self.message = message
super().__init__(f"字段 '{field}' 验证失败: {message}")
class DatabaseError(CustomBusinessError):
"""数据库操作错误"""
def __init__(self, operation, table, message):
self.operation = operation
self.table = table
self.message = message
super().__init__(f"数据库操作 '{operation}' 在表 '{table}' 上失败: {message}")
class NetworkError(CustomBusinessError):
"""网络错误"""
def __init__(self, url, status_code, message):
self.url = url
self.status_code = status_code
self.message = message
super().__init__(f"访问 {url} 失败,状态码: {status_code}, 错误: {message}")
# 使用自定义异常
def business_operation():
try:
# 模拟各种业务错误
raise ValidationError("email", "邮箱格式不正确")
# 或
# raise DatabaseError("INSERT", "users", "重复的主键")
# 或
# raise NetworkError("https://api.example.com", 500, "服务器内部错误")
except ValidationError as e:
print(f"验证错误: {e}")
print(f"错误字段: {e.field}")
except DatabaseError as e:
print(f"数据库错误: {e}")
print(f"操作: {e.operation}, 表: {e.table}")
except NetworkError as e:
print(f"网络错误: {e}")
print(f"URL: {e.url}, 状态码: {e.status_code}")
except CustomBusinessError as e:
print(f"业务错误: {e}")
异常处理最佳实践
def best_practices():
"""
异常处理最佳实践示例
"""
# 1. 具体异常优先,通用异常在后
try:
risky_operation()
except ValueError:
# 具体异常处理
pass
except TypeError:
# 具体异常处理
pass
except Exception:
# 通用异常处理(兜底)
pass
# 2. 尽量捕获特定异常,避免裸except:
# 不建议:except: # 捕获所有异常,包括SystemExit
# 3. 使用else子句(无异常时执行)
try:
result = risky_operation()
except ValueError as e:
print(f"错误: {e}")
else:
print(f"成功: {result}") # 只有在try块成功时才执行
# 4. 使用finally子句(始终执行)
file = None
try:
file = open("data.txt", 'r')
data = file.read()
except FileNotFoundError:
print("文件不存在")
finally:
if file:
file.close() # 确保文件被关闭
# 5. 异常链(保留原始异常信息)
try:
try:
int("abc")
except ValueError as e:
raise RuntimeError("数字转换失败") from e # 保留原始异常
def risky_operation():
"""模拟有风险的操作"""
import random
if random.random() < 0.5:
raise ValueError("随机错误")
return "success"
快速诊断指南
def diagnose_exception(exc):
"""
异常诊断助手函数
"""
exception_map = {
IndexError: "列表/元组索引超出范围",
KeyError: "字典键不存在",
ValueError: "值不符合预期格式",
TypeError: "操作或函数应用于不适当类型的对象",
AttributeError: "对象没有这个属性/方法",
NameError: "变量未定义",
ZeroDivisionError: "除零错误",
FileNotFoundError: "文件不存在",
ImportError: "模块导入失败",
SyntaxError: "代码语法错误",
IndentationError: "缩进错误",
}
exc_type = type(exc)
if exc_type in exception_map:
return f"{exception_map[exc_type]}: {exc}"
else:
return f"未知异常类型 {exc_type.__name__}: {exc}"
# 使用示例
try:
1/0
except Exception as e:
print(diagnose_exception(e)) # 除零错误: division by zero
- 区分方法:根据错误信息和异常类型名称判断
- 处理原则:具体异常优先,通用异常兜底
- 最佳实践:
- 只捕获你能处理的异常
- 使用自定义异常封装业务逻辑
- 保持异常链完整
- 合理使用else和finally
好的异常处理不是避免异常,而是优雅地处理异常!