网站首页 > 技术文章 正文
昨天,我们学习了文件操作,掌握了读写文件的基础技能。今天,我们将学习异常处理 — Python中处理错误和异常情况的重要机制。
异常处理让您的程序更加健壮,能够优雅地处理各种错误情况,而不是让程序崩溃。
今天您将学习什么
- 什么是异常以及异常的类型
- try-except语句的基本用法
- 多种异常处理方式
- finally和else子句
- 自定义异常类
- 真实世界示例:错误处理、资源管理、数据验证
什么是异常?
异常是程序执行过程中发生的错误或异常情况。当Python遇到无法处理的错误时,会抛出一个异常对象。
常见的异常类型:
# ValueError - 值错误
int("abc") # ValueError: invalid literal for int()
# TypeError - 类型错误
len(123) # TypeError: object of type 'int' has no len()
# IndexError - 索引错误
numbers = [1, 2, 3]
numbers[10] # IndexError: list index out of range
# KeyError - 键错误
data = {"name": "Alice"}
data["age"] # KeyError: 'age'
# FileNotFoundError - 文件未找到
open("nonexistent.txt") # FileNotFoundError
1. 基本的try-except语句
捕获单个异常
try:
number = int(input("请输入一个数字:"))
result = 10 / number
print(f"结果是:{result}")
except ValueError:
print("输入无效,请输入一个有效的数字")
except ZeroDivisionError:
print("不能除以零")
捕获多个异常
try:
number = int(input("请输入一个数字:"))
result = 10 / number
print(f"结果是:{result}")
except (ValueError, ZeroDivisionError) as e:
print(f"发生错误:{e}")
捕获所有异常(不推荐)
try:
number = int(input("请输入一个数字:"))
result = 10 / number
print(f"结果是:{result}")
except Exception as e:
print(f"发生未知错误:{e}")
2. try-except-else-finally
完整的异常处理结构
try:
# 可能出错的代码
number = int(input("请输入一个数字:"))
result = 10 / number
except ValueError:
# 处理ValueError异常
print("输入无效,请输入一个有效的数字")
except ZeroDivisionError:
# 处理ZeroDivisionError异常
print("不能除以零")
else:
# 没有异常时执行
print(f"计算成功,结果是:{result}")
finally:
# 无论是否有异常都会执行
print("程序执行完毕")
文件操作的异常处理
try:
with open('data.txt', 'r', encoding='utf-8') as file:
content = file.read()
print("文件读取成功")
except FileNotFoundError:
print("文件不存在")
except PermissionError:
print("没有权限读取文件")
except UnicodeDecodeError:
print("文件编码错误")
else:
print(f"文件内容:{content}")
finally:
print("文件操作完成")
3. 异常处理的最佳实践
具体的异常处理
# 好的做法:捕获具体异常
try:
data = {"name": "Alice"}
age = data["age"]
except KeyError:
print("键不存在")
# 不好的做法:捕获所有异常
try:
data = {"name": "Alice"}
age = data["age"]
except Exception: # 太宽泛
print("发生错误")
异常信息的处理
try:
number = int("abc")
except ValueError as e:
print(f"值错误:{e}")
print(f"错误类型:{type(e).__name__}")
# 可以记录日志或发送错误报告
真实世界示例1:数据验证系统
class DataValidator:
def __init__(self):
self.errors = []
def validate_age(self, age_str):
"""验证年龄"""
try:
age = int(age_str)
if age < 0 or age > 150:
raise ValueError("年龄必须在0-150之间")
return age
except ValueError as e:
self.errors.append(f"年龄验证失败:{e}")
return None
def validate_email(self, email):
"""验证邮箱格式"""
try:
if '@' not in email or '.' not in email:
raise ValueError("邮箱格式不正确")
if len(email) < 5:
raise ValueError("邮箱长度太短")
return email
except ValueError as e:
self.errors.append(f"邮箱验证失败:{e}")
return None
def validate_user_data(self, user_data):
"""验证用户数据"""
validated_data = {}
# 验证姓名
try:
name = user_data.get('name', '').strip()
if not name:
raise ValueError("姓名不能为空")
if len(name) < 2:
raise ValueError("姓名长度太短")
validated_data['name'] = name
except ValueError as e:
self.errors.append(f"姓名验证失败:{e}")
# 验证年龄
age = self.validate_age(user_data.get('age', ''))
if age is not None:
validated_data['age'] = age
# 验证邮箱
email = self.validate_email(user_data.get('email', ''))
if email is not None:
validated_data['email'] = email
return validated_data
def get_errors(self):
"""获取所有错误信息"""
return self.errors.copy()
def has_errors(self):
"""检查是否有错误"""
return len(self.errors) > 0
# 使用示例
validator = DataValidator()
# 测试数据
test_data = {
'name': 'A', # 姓名太短
'age': 'abc', # 年龄格式错误
'email': 'invalid-email' # 邮箱格式错误
}
validated_data = validator.validate_user_data(test_data)
if validator.has_errors():
print("验证失败,错误信息:")
for error in validator.get_errors():
print(f" - {error}")
else:
print("验证成功!")
print(f"有效数据:{validated_data}")
真实世界示例2:安全的文件操作
import os
from pathlib import Path
class SafeFileManager:
def __init__(self, base_dir="data"):
self.base_dir = Path(base_dir)
self.base_dir.mkdir(exist_ok=True)
def safe_read_file(self, filename):
"""安全读取文件"""
file_path = self.base_dir / filename
try:
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
return {"success": True, "data": content}
except FileNotFoundError:
return {"success": False, "error": "文件不存在"}
except PermissionError:
return {"success": False, "error": "没有读取权限"}
except UnicodeDecodeError:
return {"success": False, "error": "文件编码错误"}
except Exception as e:
return {"success": False, "error": f"未知错误:{e}"}
def safe_write_file(self, filename, content):
"""安全写入文件"""
file_path = self.base_dir / filename
try:
# 检查目录是否存在
file_path.parent.mkdir(parents=True, exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as file:
file.write(content)
return {"success": True, "message": "文件写入成功"}
except PermissionError:
return {"success": False, "error": "没有写入权限"}
except OSError as e:
return {"success": False, "error": f"系统错误:{e}"}
except Exception as e:
return {"success": False, "error": f"未知错误:{e}"}
def safe_delete_file(self, filename):
"""安全删除文件"""
file_path = self.base_dir / filename
try:
if file_path.exists():
file_path.unlink()
return {"success": True, "message": "文件删除成功"}
else:
return {"success": False, "error": "文件不存在"}
except PermissionError:
return {"success": False, "error": "没有删除权限"}
except Exception as e:
return {"success": False, "error": f"删除失败:{e}"}
# 使用示例
file_manager = SafeFileManager("test_data")
# 写入文件
result = file_manager.safe_write_file("test.txt", "Hello, World!")
print(result)
# 读取文件
result = file_manager.safe_read_file("test.txt")
if result["success"]:
print(f"文件内容:{result['data']}")
else:
print(f"读取失败:{result['error']}")
# 删除文件
result = file_manager.safe_delete_file("test.txt")
print(result)
真实世界示例3:计算器应用
class Calculator:
def __init__(self):
self.history = []
def add(self, a, b):
"""加法运算"""
try:
result = float(a) + float(b)
self.history.append(f"{a} + {b} = {result}")
return result
except (ValueError, TypeError) as e:
raise ValueError(f"无效的操作数:{e}")
def subtract(self, a, b):
"""减法运算"""
try:
result = float(a) - float(b)
self.history.append(f"{a} - {b} = {result}")
return result
except (ValueError, TypeError) as e:
raise ValueError(f"无效的操作数:{e}")
def multiply(self, a, b):
"""乘法运算"""
try:
result = float(a) * float(b)
self.history.append(f"{a} * {b} = {result}")
return result
except (ValueError, TypeError) as e:
raise ValueError(f"无效的操作数:{e}")
def divide(self, a, b):
"""除法运算"""
try:
if float(b) == 0:
raise ValueError("除数不能为零")
result = float(a) / float(b)
self.history.append(f"{a} / {b} = {result}")
return result
except (ValueError, TypeError) as e:
raise ValueError(f"无效的操作数:{e}")
def calculate(self, expression):
"""计算表达式"""
try:
# 简单的表达式解析(仅支持基本运算)
parts = expression.split()
if len(parts) != 3:
raise ValueError("表达式格式错误,应为:数字 运算符 数字")
a, operator, b = parts
if operator == '+':
return self.add(a, b)
elif operator == '-':
return self.subtract(a, b)
elif operator == '*':
return self.multiply(a, b)
elif operator == '/':
return self.divide(a, b)
else:
raise ValueError(f"不支持的运算符:{operator}")
except ValueError as e:
print(f"计算错误:{e}")
return None
def get_history(self):
"""获取计算历史"""
return self.history.copy()
# 使用示例
calc = Calculator()
# 测试各种计算
test_expressions = [
"10 + 5",
"10 - 3",
"4 * 6",
"15 / 3",
"10 / 0", # 会出错
"abc + 5", # 会出错
"10 + 5 + 3" # 格式错误
]
for expr in test_expressions:
print(f"计算:{expr}")
result = calc.calculate(expr)
if result is not None:
print(f"结果:{result}")
print()
# 显示计算历史
print("计算历史:")
for entry in calc.get_history():
print(f" {entry}")
4. 自定义异常类
class ValidationError(Exception):
"""自定义验证错误异常"""
def __init__(self, message, field=None):
self.message = message
self.field = field
super().__init__(self.message)
class DatabaseError(Exception):
"""自定义数据库错误异常"""
def __init__(self, message, error_code=None):
self.message = message
self.error_code = error_code
super().__init__(self.message)
# 使用自定义异常
def validate_user_age(age):
try:
age_int = int(age)
if age_int < 0:
raise ValidationError("年龄不能为负数", "age")
if age_int > 150:
raise ValidationError("年龄不能超过150", "age")
return age_int
except ValueError:
raise ValidationError("年龄必须是数字", "age")
# 测试自定义异常
try:
age = validate_user_age("200")
except ValidationError as e:
print(f"验证错误:{e.message}")
if e.field:
print(f"错误字段:{e.field}")
异常处理的最佳实践
推荐做法:
- 捕获具体的异常类型
- 提供有意义的错误信息
- 使用finally确保资源清理
- 适当记录错误日志
避免的做法:
- 捕获所有异常而不处理
- 忽略异常
- 在except块中使用pass
- 过度使用异常处理
异常处理的高级技巧
上下文管理器
class DatabaseConnection:
def __init__(self, host, port):
self.host = host
self.port = port
self.connection = None
def __enter__(self):
try:
# 模拟数据库连接
print(f"连接到数据库 {self.host}:{self.port}")
self.connection = "connected"
return self
except Exception as e:
print(f"连接失败:{e}")
raise
def __exit__(self, exc_type, exc_val, exc_tb):
if self.connection:
print("关闭数据库连接")
self.connection = None
# 使用上下文管理器
try:
with DatabaseConnection("localhost", 5432) as db:
print("执行数据库操作")
# 模拟操作失败
raise Exception("操作失败")
except Exception as e:
print(f"操作失败:{e}")
回顾
今天您学习了:
- 异常的基本概念和类型
- try-except语句的使用
- 完整的异常处理结构
- 自定义异常类
- 真实世界应用:数据验证、文件操作、计算器
异常处理是编写健壮程序的重要技能,掌握这些知识将让您的程序更加可靠!
猜你喜欢
- 2025-08-05 python学习笔记 1.常见的数据类型
- 2025-08-05 从进阶语法到实战应用:Python中级修炼指南
- 2025-08-05 Python 面试问题:运算符
- 2025-08-05 Python解析库lxml与xpath用法总结
- 2025-08-05 Python从1到N整数求和的方法汇总
- 2025-08-05 Python语言从2.7到3.14的能力变化与演进逻辑
- 2025-08-05 第八章:Python异常处理
- 2025-08-05 72岁老翁学python编程(四)
- 2025-08-05 Python运算符探秘:掌握编程艺术的秘密武器
- 2025-08-05 用Python实现素数相关算法并做注释说明
- 08-06生产环境中使用的十大 Python 设计模式
- 08-06面试必备:Python内存管理机制(建议收藏)
- 08-06服务端开发面试必背——消息队列及它的主要用途和优点。附代码
- 08-06Python 栈:深度解析与应用
- 08-06Python中的多进程
- 08-06Python Logging 最佳实践
- 08-06Python并发数据结构实现原理
- 08-06用SendGrid和Redis队列用Python调度国际空间站的电子邮件
- 最近发表
- 标签列表
-
- python中类 (31)
- python 迭代 (34)
- python 小写 (35)
- python怎么输出 (33)
- python 日志 (35)
- python语音 (31)
- python 工程师 (34)
- python3 安装 (31)
- python音乐 (31)
- 安卓 python (32)
- python 小游戏 (32)
- python 安卓 (31)
- python聚类 (34)
- python向量 (31)
- python大全 (31)
- python次方 (33)
- python桌面 (32)
- python总结 (34)
- python浏览器 (32)
- python 请求 (32)
- python 前端 (32)
- python验证码 (33)
- python 题目 (32)
- python 文件写 (33)
- python中的用法 (32)