Appearance
⚠️ Python 异常处理
异常处理概述
异常处理是编程中处理错误和异常情况的重要机制。Python 提供了强大的异常处理系统,让程序能够优雅地处理各种错误情况。
💡 为什么需要异常处理?: - 提高程序健壮性:程序不会因为错误而崩溃 - 提供错误信息:帮助开发者定位和解决问题 - 优雅降级:在错误发生时提供备用方案 - 用户体验:给用户友好的错误提示
🚨 异常类型
常见内置异常
python
# 除零错误
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"除零错误: {e}")
# 类型错误
try:
result = "hello" + 5
except TypeError as e:
print(f"类型错误: {e}")
# 值错误
try:
number = int("abc")
except ValueError as e:
print(f"值错误: {e}")
# 索引错误
try:
numbers = [1, 2, 3]
print(numbers[10])
except IndexError as e:
print(f"索引错误: {e}")
# 键错误
try:
person = {"name": "张三"}
print(person["age"])
except KeyError as e:
print(f"键错误: {e}")
# 文件不存在错误
try:
with open("不存在的文件.txt", "r") as f:
content = f.read()
except FileNotFoundError as e:
print(f"文件不存在: {e}")异常层次结构
python
# 查看异常层次结构
import builtins
def print_exception_hierarchy(exception_class, indent=0):
"""打印异常层次结构"""
print(" " * indent + exception_class.__name__)
for subclass in exception_class.__subclasses__():
print_exception_hierarchy(subclass, indent + 1)
# 打印主要异常层次
print("Python 异常层次结构:")
print_exception_hierarchy(BaseException)🛡️ try-except 语句
基本异常处理
python
def safe_divide(a, b):
"""安全除法函数"""
try:
result = a / b
return result
except ZeroDivisionError:
print("错误:除数不能为零")
return None
except TypeError:
print("错误:参数类型不正确")
return None
# 测试异常处理
print(safe_divide(10, 2)) # 正常情况
print(safe_divide(10, 0)) # 除零错误
print(safe_divide(10, "2")) # 类型错误多个异常处理
python
def process_user_input(user_input):
"""处理用户输入"""
try:
# 尝试转换为整数
number = int(user_input)
# 尝试计算平方根
import math
result = math.sqrt(number)
return f"√{number} = {result:.2f}"
except ValueError:
return "错误:请输入有效的数字"
except TypeError:
return "错误:输入类型不正确"
except Exception as e:
return f"未知错误:{e}"
# 测试多种情况
test_inputs = ["16", "abc", "-4", "0"]
for inp in test_inputs:
print(f"输入: {inp} -> {process_user_input(inp)}")捕获所有异常
python
def risky_operation():
"""可能出错的操作"""
try:
# 模拟可能出错的操作
data = {"name": "张三", "age": 25}
print(data["name"])
print(data["age"])
# 故意制造错误
print(data["salary"]) # 键不存在
except Exception as e:
print(f"发生错误: {type(e).__name__}: {e}")
print("程序继续执行...")
risky_operation()🔄 try-except-else-finally
完整的异常处理结构
python
def file_operations(filename):
"""文件操作示例"""
file = None
try:
# 尝试打开文件
file = open(filename, 'r')
content = file.read()
print("文件读取成功")
except FileNotFoundError:
print(f"错误:文件 {filename} 不存在")
except PermissionError:
print(f"错误:没有权限访问文件 {filename}")
except Exception as e:
print(f"未知错误:{e}")
else:
# 没有异常时执行
print("文件操作完成,没有发生异常")
return content
finally:
# 无论是否发生异常都会执行
if file:
file.close()
print("文件已关闭")
# 测试文件操作
file_operations("test.txt")实际应用示例
python
def safe_json_parse(json_string):
"""安全解析JSON字符串"""
import json
try:
data = json.loads(json_string)
print("JSON解析成功")
except json.JSONDecodeError as e:
print(f"JSON格式错误:{e}")
return None
except Exception as e:
print(f"其他错误:{e}")
return None
else:
print("JSON数据有效")
return data
finally:
print("JSON解析操作完成")
# 测试JSON解析
valid_json = '{"name": "张三", "age": 25}'
invalid_json = '{"name": "张三", "age": 25' # 缺少右括号
safe_json_parse(valid_json)
print("-" * 30)
safe_json_parse(invalid_json)🎯 自定义异常
创建自定义异常
python
class CustomError(Exception):
"""自定义异常基类"""
pass
class ValidationError(CustomError):
"""验证错误"""
def __init__(self, message, field=None):
self.message = message
self.field = field
super().__init__(self.message)
class BusinessLogicError(CustomError):
"""业务逻辑错误"""
def __init__(self, message, error_code=None):
self.message = message
self.error_code = error_code
super().__init__(self.message)
# 使用自定义异常
def validate_age(age):
"""验证年龄"""
if not isinstance(age, int):
raise ValidationError("年龄必须是整数", "age")
if age < 0:
raise ValidationError("年龄不能为负数", "age")
if age > 150:
raise ValidationError("年龄不能超过150岁", "age")
return True
def process_user_data(name, age):
"""处理用户数据"""
try:
validate_age(age)
if len(name) < 2:
raise BusinessLogicError("姓名太短", "NAME_TOO_SHORT")
return f"用户 {name},年龄 {age} 验证通过"
except ValidationError as e:
return f"验证失败:{e.message} (字段: {e.field})"
except BusinessLogicError as e:
return f"业务逻辑错误:{e.message} (错误代码: {e.error_code})"
# 测试自定义异常
print(process_user_data("张三", 25)) # 正常
print(process_user_data("张", 25)) # 姓名太短
print(process_user_data("张三", -5)) # 年龄为负
print(process_user_data("张三", "25")) # 年龄类型错误异常链
python
class DatabaseError(Exception):
"""数据库错误"""
pass
class UserService:
"""用户服务类"""
def get_user(self, user_id):
try:
# 模拟数据库操作
if user_id < 0:
raise DatabaseError("用户ID不能为负数")
return {"id": user_id, "name": f"用户{user_id}"}
except DatabaseError as e:
# 重新抛出异常,保留原始异常信息
raise UserServiceError(f"获取用户失败: {e}") from e
class UserServiceError(Exception):
"""用户服务错误"""
pass
# 测试异常链
service = UserService()
try:
user = service.get_user(-1)
except UserServiceError as e:
print(f"用户服务错误: {e}")
print(f"原始错误: {e.__cause__}")🔧 异常处理最佳实践
具体异常处理
python
# 好的做法:捕获具体异常
def good_practice():
try:
with open("config.json", "r") as f:
config = f.read()
except FileNotFoundError:
print("配置文件不存在,使用默认配置")
except PermissionError:
print("没有权限读取配置文件")
except Exception as e:
print(f"读取配置文件时发生未知错误: {e}")
# 不好的做法:捕获所有异常
def bad_practice():
try:
with open("config.json", "r") as f:
config = f.read()
except: # 太宽泛
print("发生错误")异常处理中的资源管理
python
class DatabaseConnection:
"""数据库连接类"""
def __init__(self, host, port):
self.host = host
self.port = port
self.connected = False
def connect(self):
"""连接数据库"""
try:
# 模拟连接过程
if self.port < 0:
raise ConnectionError("端口号不能为负数")
self.connected = True
print(f"已连接到 {self.host}:{self.port}")
except ConnectionError as e:
print(f"连接失败: {e}")
raise
def disconnect(self):
"""断开连接"""
if self.connected:
self.connected = False
print("数据库连接已断开")
def __enter__(self):
"""上下文管理器入口"""
self.connect()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""上下文管理器出口"""
self.disconnect()
if exc_type:
print(f"操作过程中发生异常: {exc_type.__name__}")
return False # 不抑制异常
# 使用上下文管理器
try:
with DatabaseConnection("localhost", 3306) as db:
print("执行数据库操作...")
# 模拟操作
if db.connected:
print("操作成功")
except ConnectionError as e:
print(f"数据库操作失败: {e}")日志记录
python
import logging
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def process_data(data):
"""处理数据,记录异常"""
try:
# 模拟数据处理
if not data:
raise ValueError("数据不能为空")
result = [x * 2 for x in data]
logging.info(f"数据处理成功,处理了 {len(data)} 条记录")
return result
except ValueError as e:
logging.error(f"数据验证失败: {e}")
raise
except Exception as e:
logging.error(f"数据处理时发生未知错误: {e}")
raise
# 测试日志记录
try:
result = process_data([1, 2, 3, 4, 5])
print(f"处理结果: {result}")
except Exception as e:
print(f"处理失败: {e}")🎯 实践练习
练习1:计算器异常处理
编写一个安全的计算器,处理以下异常:
- 除零错误
- 无效输入
- 数学运算错误
练习2:文件处理异常
编写一个文件处理程序,处理:
- 文件不存在
- 权限不足
- 文件格式错误
- 磁盘空间不足
练习3:网络请求异常
模拟网络请求,处理:
- 连接超时
- 网络不可达
- 服务器错误
- 数据格式错误
练习4:用户输入验证
创建一个用户注册系统,验证:
- 用户名格式
- 密码强度
- 邮箱格式
- 年龄范围
🔍 调试技巧
异常信息分析
python
import traceback
def analyze_exception():
"""分析异常信息"""
try:
# 故意制造一个复杂的异常
data = {"users": [{"name": "张三", "age": 25}]}
user = data["users"][1] # 索引超出范围
print(user["salary"]) # 键不存在
except Exception as e:
print(f"异常类型: {type(e).__name__}")
print(f"异常信息: {e}")
print(f"异常参数: {e.args}")
print("\n完整异常信息:")
traceback.print_exc()
analyze_exception()异常处理装饰器
python
def handle_exceptions(func):
"""异常处理装饰器"""
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"函数 {func.__name__} 发生异常: {e}")
return None
return wrapper
@handle_exceptions
def risky_function(x, y):
"""可能出错的函数"""
return x / y
# 使用装饰器
result = risky_function(10, 0)
print(f"结果: {result}")📊 异常处理总结
异常处理原则
- 具体优于宽泛:捕获具体异常而不是所有异常
- 早发现早处理:在问题发生的地方处理异常
- 提供有用信息:异常信息应该帮助定位问题
- 优雅降级:提供备用方案或默认值
- 记录日志:记录异常信息用于调试
- 资源清理:使用 finally 或上下文管理器清理资源
常见异常类型
| 异常类型 | 描述 | 常见场景 |
|---|---|---|
| ValueError | 值错误 | 类型转换失败 |
| TypeError | 类型错误 | 操作不支持的类型 |
| IndexError | 索引错误 | 列表索引超出范围 |
| KeyError | 键错误 | 字典键不存在 |
| FileNotFoundError | 文件不存在 | 打开不存在的文件 |
| ZeroDivisionError | 除零错误 | 除数为零 |
下一步
现在你已经掌握了 Python 的异常处理,接下来学习:
💡 学习建议:多练习异常处理,提高程序的健壮性和用户体验
