文章目录
- 前言
- 一、异常处理基础
-
- [1. 基本语法结构](#1. 基本语法结构)
- [2. 为什么要用try-except?](#2. 为什么要用try-except?)
- [3. 捕获特定异常](#3. 捕获特定异常)
- 二、完整的异常处理结构
-
- [1. try-except-else-finally完整结构](#1. try-except-else-finally完整结构)
- [2. 捕获多个异常](#2. 捕获多个异常)
- 三、异常对象和自定义异常
-
- [1. 获取异常信息](#1. 获取异常信息)
- [2. 自定义异常](#2. 自定义异常)
- [3. 异常链](#3. 异常链)
- 四、实际应用场景
-
- [1. 用户输入验证](#1. 用户输入验证)
前言
本文主要介绍异常处理基础、完整的异常处理结构、异常对象和自定义异常以及应用场景等知识点。
一、异常处理基础
1. 基本语法结构
python
python
try:
# 可能出错的代码
代码块
except 异常类型:
# 处理异常的代码
处理代码
2. 为什么要用try-except?
python
python
# 没有异常处理的代码会直接崩溃
print("程序开始")
# 这些代码可能会出错
number = int("abc") # 这里会崩溃!
print(f"数字是: {number}")
print("程序结束") # 这行永远不会执行
# 使用try-except可以让程序继续运行
print("\n=== 使用try-except ===")
print("程序开始")
try:
number = int("abc") # 这行会出错
print(f"数字是: {number}")
except ValueError:
print("错误:无法将字符串转换为整数")
print("程序正常结束") # 这行会执行
3. 捕获特定异常
python
python
# 示例1:处理除零错误
def divide_numbers(a, b):
"""除法运算,处理除零错误"""
try:
result = a / b
return result
except ZeroDivisionError:
return "错误:除数不能为零"
print("除法测试:")
print(f"10 / 2 = {divide_numbers(10, 2)}")
print(f"10 / 0 = {divide_numbers(10, 0)}")
# 示例2:处理文件不存在错误
def read_file(filename):
"""读取文件,处理文件不存在的情况"""
try:
with open(filename, 'r', encoding='utf-8') as file:
content = file.read()
return content
except FileNotFoundError:
return f"错误:文件 '{filename}' 不存在"
except PermissionError:
return f"错误:没有权限读取文件 '{filename}'"
print("\n文件读取测试:")
print(read_file("存在的文件.txt")) # 如果文件存在
print(read_file("不存在的文件.txt")) # 文件不存在
二、完整的异常处理结构
1. try-except-else-finally完整结构
python
python
def process_data(data_str):
"""
完整的异常处理示例
try-except-else-finally结构
"""
result = None
try:
print("尝试处理数据...")
# 可能出错的代码
number = float(data_str)
result = number * 2
except ValueError:
print(f"错误:'{data_str}' 不是有效的数字")
except TypeError:
print("错误:输入类型不正确")
else:
# 只有当try块没有异常时才执行
print(f"处理成功!原始数据: {data_str}, 结果: {result}")
finally:
# 无论是否发生异常都会执行
print("清理资源...")
print("-" * 40)
return result
# 测试各种情况
print("测试1:正常数据")
process_data("10.5")
print("测试2:无效数据")
process_data("abc")
print("测试3:None值")
process_data(None)
# finally的典型应用场景
def read_config_file(filename):
"""读取配置文件,确保文件被关闭"""
file = None
try:
file = open(filename, 'r', encoding='utf-8')
content = file.read()
config = eval(content) # 危险!仅作示例
return config
except FileNotFoundError:
print(f"配置文件 {filename} 不存在")
return {}
except SyntaxError:
print(f"配置文件 {filename} 格式错误")
return {}
finally:
# 确保文件总是被关闭
if file and not file.closed:
file.close()
print(f"已关闭文件: {filename}")
2. 捕获多个异常
python
python
# 方法1:多个except块
def handle_multiple_errors_1(data):
"""多个except块处理不同异常"""
try:
# 多种可能的错误
index = int(data)
numbers = [10, 20, 30, 40, 50]
result = numbers[index] / (index - 2) # 可能除零
return f"结果: {result}"
except ValueError:
return "错误:请输入有效的整数"
except IndexError:
return "错误:索引超出范围,有效索引是0-4"
except ZeroDivisionError:
return "错误:除数不能为零(索引不能为2)"
except Exception as e:
# 捕获其他所有异常
return f"未知错误: {type(e).__name__}: {e}"
# 测试
test_cases = ["abc", "10", "2", "3", "0"]
for test in test_cases:
print(f"输入 '{test}': {handle_multiple_errors_1(test)}")
# 方法2:一个except块捕获多个异常
def handle_multiple_errors_2(data):
"""一个except块捕获多个异常"""
try:
index = int(data)
numbers = [10, 20, 30, 40, 50]
result = numbers[index] / (index - 2)
return f"结果: {result}"
except (ValueError, IndexError, ZeroDivisionError) as e:
# 处理多种异常
error_type = type(e).__name__
if error_type == "ValueError":
return "错误:请输入有效的整数"
elif error_type == "IndexError":
return "错误:索引超出范围"
elif error_type == "ZeroDivisionError":
return "错误:除数不能为零"
except Exception as e:
return f"其他错误: {e}"
print("\n" + "="*40 + "\n")
for test in test_cases:
print(f"输入 '{test}': {handle_multiple_errors_2(test)}")
三、异常对象和自定义异常
1. 获取异常信息
python
python
def analyze_error(data):
"""分析异常信息"""
try:
result = 100 / int(data)
return f"成功: {result}"
except Exception as e:
# 获取异常的详细信息
print(f"异常类型: {type(e).__name__}")
print(f"异常信息: {e}")
print(f"异常参数: {e.args}")
# 获取更多调试信息
import traceback
print("\n异常追踪:")
traceback.print_exc()
return f"失败: {type(e).__name__}"
print("分析错误信息:")
print(analyze_error("0"))
print("\n" + "="*40)
print(analyze_error("abc"))
2. 自定义异常
python
python
# 创建自定义异常类
class ValidationError(Exception):
"""自定义验证错误"""
def __init__(self, message, field=None):
super().__init__(message)
self.field = field
self.message = message
def __str__(self):
if self.field:
return f"{self.field}字段验证失败: {self.message}"
return f"验证失败: {self.message}"
class InsufficientBalanceError(Exception):
"""余额不足错误"""
def __init__(self, balance, amount):
super().__init__(f"余额不足: 当前余额{balance},需要{amount}")
self.balance = balance
self.amount = amount
# 使用自定义异常
def validate_user_input(username, password):
"""验证用户输入"""
if not username or not username.strip():
raise ValidationError("用户名不能为空", field="username")
if len(password) < 6:
raise ValidationError("密码长度至少6位", field="password")
if not any(c.isdigit() for c in password):
raise ValidationError("密码必须包含数字", field="password")
print("验证通过!")
return True
def withdraw_money(balance, amount):
"""取款操作"""
if amount <= 0:
raise ValueError("取款金额必须大于0")
if amount > balance:
raise InsufficientBalanceError(balance, amount)
balance -= amount
print(f"取款成功!剩余余额: {balance}")
return balance
# 测试自定义异常
print("测试1:用户验证")
try:
validate_user_input("", "123")
except ValidationError as e:
print(f"捕获到验证错误: {e}")
print(f"错误字段: {e.field}")
print("\n测试2:取款操作")
try:
withdraw_money(1000, 1500)
except InsufficientBalanceError as e:
print(f"捕获到余额不足错误: {e}")
print(f"当前余额: {e.balance}, 需要金额: {e.amount}")
except ValueError as e:
print(f"捕获到值错误: {e}")
print("\n测试3:链式异常处理")
try:
try:
validate_user_input("admin", "123")
except ValidationError as e:
print(f"内层捕获: {e}")
# 可以重新抛出异常
raise # 重新抛出当前异常
except ValidationError as e:
print(f"外层捕获: {e}")
3. 异常链
python
python
def process_data_file(filename):
"""处理数据文件,演示异常链"""
try:
with open(filename, 'r') as file:
data = file.read()
numbers = [int(x) for x in data.split()]
average = sum(numbers) / len(numbers)
return average
except FileNotFoundError as e:
# 添加更多上下文信息
raise FileNotFoundError(f"无法处理文件 '{filename}'") from e
except ValueError as e:
# 转换异常类型
raise RuntimeError(f"文件 '{filename}' 包含无效数据") from e
# 测试异常链
try:
result = process_data_file("nonexistent.txt")
except Exception as e:
print(f"主错误: {e}")
print(f"原因: {e.__cause__}")
# 显示完整的异常链
import traceback
print("\n完整异常链:")
traceback.print_exc()
四、实际应用场景
1. 用户输入验证
python
python
def get_valid_number(prompt, min_value=None, max_value=None):
"""获取有效的数字输入"""
while True:
try:
user_input = input(prompt)
number = float(user_input)
# 验证范围
if min_value is not None and number < min_value:
raise ValueError(f"数字不能小于 {min_value}")
if max_value is not None and number > max_value:
raise ValueError(f"数字不能大于 {max_value}")
return number
except ValueError as e:
if "could not convert" in str(e):
print(f"错误: '{user_input}' 不是有效的数字")
else:
print(f"错误: {e}")
print("请重新输入...\n")
# 使用
print("用户输入验证示例:")
age = get_valid_number("请输入年龄(0-150): ", min_value=0, max_value=150)
temperature = get_valid_number("请输入温度(-50 to 60): ", min_value=-50, max_value=60)
print(f"年龄: {age:.0f}岁")
print(f"温度: {temperature:.1f}°C")