Python教程(二十):异常处理 try、except、finally
ztj100 2025-08-01 22:14 4 浏览 0 评论
昨天,我们学习了文件操作,掌握了读写文件的基础技能。今天,我们将学习异常处理 — 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语句的使用
- 完整的异常处理结构
- 自定义异常类
- 真实世界应用:数据验证、文件操作、计算器
异常处理是编写健壮程序的重要技能,掌握这些知识将让您的程序更加可靠!
- 上一篇:微信支付接入
- 下一篇:ECC加密算法Illegal key size错误源码详解
相关推荐
- Java的SPI机制详解
-
作者:京东物流杨苇苇1.SPI简介SPI(ServiceProvicerInterface)是Java语言提供的一种接口发现机制,用来实现接口和接口实现的解耦。简单来说,就是系统只需要定义接口规...
- 一文读懂 Spring Boot 启动原理,开发效率飙升!
-
在当今的Java开发领域,SpringBoot无疑是最热门的框架之一。它以其“约定大于配置”的理念,让开发者能够快速搭建和启动应用,极大地提高了开发效率。但是,你是否真正了解Spring...
- ServiceLoader
-
ServiceLoader是Java提供的一种服务发现机制(ServiceProviderInterface,SPI)...
- 深入探索 Spring Boot3 中的自定义扩展操作
-
在当今互联网软件开发领域,SpringBoot无疑是最受欢迎的框架之一。随着其版本迭代至SpringBoot3,它为开发者们带来了更多强大的功能和特性,其中自定义扩展操作更是为我们在项目开发中...
- Spring Boot启动过程全面解析:从入门到精通
-
一、SpringBoot概述SpringBoot是一个基于Spring框架的快速开发脚手架,它通过"约定优于配置"的原则简化了Spring应用的初始搭建和开发过程。...
- Spring Boot 3.x 自定义 Starter 详解
-
今天星期六,继续卷springboot3.x。在SpringBoot3.x中,自定义Starter是封装和共享通用功能、实现“约定优于配置”理念的强大机制。通过创建自己的Starte...
- Spring Boot 的 3 种动态 Bean 注入技巧
-
在SpringBoot开发中,动态注入Bean是一种强大的技术,它允许我们根据特定条件或运行时环境灵活地创建和管理Bean。相比于传统的静态Bean定义,动态注入提供了更高的灵活性和可...
- 大佬用4000字带你彻底理解SpringBoot的运行原理!
-
SpringBoot的运行原理从前面创建的SpringBoot应用示例中可以看到,启动一个SpringBoot工程都是从SpringApplication.run()方法开始的。这个方法具体完成...
- Springboot是如何实现自动配置的
-
SpringBoot的自动配置功能极大地简化了基于Spring的应用程序的配置过程。它能够根据类路径中的依赖和配置文件中的属性,自动配置应用程序。下面是SpringBoot实现自动配置的...
- Spring Boot3.x 应用的生命周期深度解析
-
SpringBoot应用的生命周期可以清晰地划分为三个主要阶段:启动阶段(Startup)...
- Springboot 启动流程及各类事件生命周期那点事
-
前言本文通过Springboot启动方法分析SpringApplication逻辑。从静态run方法执行到各个阶段发布不同事件完成整个应用启动。...
- Spring框架基础知识-常用的接口1
-
BeanDefinition基本概念BeanDefinition是Spring框架中描述bean配置信息的核心接口,它包含了创建bean实例所需的所有元数据。...
- Java 技术岗面试全景备战!从基础到架构的系统性通关攻略分享
-
Java技术岗的面试往往是一项多维度的能力检验。本文将会从核心知识点、项目经验到面试策略,为你梳理一份系统性的备战攻略!...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)