Python异常处理(七)
Python异常处理(七)
python学习之旅(七) 学习汇总入口【Python】学习汇总(3万字+思维导图) 笔记PDF下载:知识笔记:Python异常处理(七) 文末附带全文概览思维导图 写作不易,如果您觉得写的不错,欢迎给博主来一波点赞、收藏~让博主更有动力吧!
一.什么是异常
程序运行的过程中出现了错误
- 定义:在程序运行中,检测到一个错误,程序中止运行并且出现了一些错误的提示,也称作
BUG - 例如:读取一个不存在的文件
f = open("C:/code/观止.txt", "r")

二.为什么要捕获异常
避免程序中止,提前准备处理可能出现的异常
- 在真实工作中, 我们肯定不能因为一个小的BUG就让整个程序全部奔溃,而是对BUG进行提醒, 整个程序继续运行
三.如何捕获异常
在可能出现异常的地方,做好提前准备,当真的出现异常的时候,可以有后续手段。
(1) 捕获常规异常
- 基本语法:
try:
可能发生错误的代码
except:
如果出现异常执行的代码
# 未发生错误try全部代码都会执行
# 未发生错误不会执行except中的代码
# 发生错误try中只会执行到报错行为止的代码
# 发生错误会执行except中的代码
使用示例:
- 首次执行,文件不存在,程序未报错中止,而是转而执行
except中代码,创建文件
try: print("r模式打开") # 执行 f = open("C:/code/观止.txt", "r") # 报错 print("r模式打开") # 不执行 except: print("w模式打开") # 执行 f = open("C:/code/观止.txt", "w") # 执行 print("w模式打开") # 执行- 首次执行,文件不存在,程序未报错中止,而是转而执行

- 第二次执行,文件存在,程序无异常,只执行try中代码
try:
print("r模式打开") # 执行
f = open("C:/code/观止.txt", "r") # 执行
print("r模式打开") # 执行
except:
print("w模式打开") # 不执行
f = open("C:/code/观止.txt", "w") # 不执行
print("w模式打开") # 不执行

(2) 捕获特定异常
- 如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常。
- 基本语法:
try:
可能发生错误的代码
except 待捕获异常名 as 别名:
如果出现异常执行的代码
例如:
- 捕获未定义变量产生的错误
try: print(name) # 未定义变量,报错 except NameError as e: print('name变量名称未定义错误')

- 同样的代码却无法捕获处理找不到文件异常
try:
f = open("C:/code/study.txt", "r") # 文件不存在,报错
except NameError as e:
print('文件不存在')

(3) 捕获多个异常
格式一:当待捕获异常名为
Exception可以捕获所有类型异常,作用与(1)一致- 例如:
try: f = open("C:/code/study.txt", "r") except Exception as e: print('文件不存在')

- 格式二:把要捕获的异常类型的名字,放到except 后,并使用元组的方式进行书写。
- 基本格式:
try:
可能发生错误的代码
except (异常名1,异常名2) as 别名:
如果出现异常执行的代码
- 使用示例:
# 示例一:
try:
f = open("C:/code/study.txt", "r")
except (FileNotFoundError, NameError) as e:
print('文件不存在')
# 示例二:
try:
print(name)
except (FileNotFoundError, NameError) as e:
print('名称未定义')
- 指定的两种异常都能捕获,未指定的无法捕获到

(4) 其他用法
(4.1) 打印异常信息
- 异常描述信息存贮在别名中,可以通过打印别名获取
- 使用示例:
try:
print(num) # 未定义,报错
except (NameError, ZeroDivisionError) as e:
print(e) # 打印 name 'num' is not defined

(4.2) 异常else
else表示的是如果没有异常要执行的代码。
使用示例:
- 出现异常,打印结果与(4.2)一致
try: print(num) # 未定义,报错 except (NameError, ZeroDivisionError) as e: print(e) # 打印 name 'num' is not defined else: print("无异常") # 有异常,不执行- 无异常
try:
print("正常") # 不报错
except (NameError, ZeroDivisionError) as e:
print(e) # 不执行
else:
print("无异常") # 执行

(4.3) 异常finally
finally表示的是无论是否异常都要执行的代码
使用示例:
- 之前提过,如果open文件却一直未close且程序未中止,将一直占用文件无法操作
- 如果打开文件后发生异常,未close也将导致一直占用,因此可选择在finally中close
global f try: f = open("C:/code/aaa.txt", "r") except Exception as e: print(e) finally: f.close() # 一定会执行close操作
四.异常的传递
异常是具有传递性的(向上一级抛出)
- 当函数调用链中出现异常,如果所有函数都没有捕获异常的时候, 程序就会报错

- 利用异常具有传递性的特点, 当我们想要保证程序不会因为异常崩溃的时候, 就可以在主函数中设置异常捕获, 由于无论在整个程序哪里发生异常, 最终都会传递到主函数中, 这样就可以确保所有的异常都会被统一捕获
五. 抛出异常
异常是什么
在 Python 中,异常是程序执行过程中发生的错误事件,它会中断程序的正常执行流程。Python 内置了多种异常类型,如 SyntaxError(语法错误)、TypeError(类型错误)、ValueError(值错误)等。当程序遇到异常时,如果没有进行相应的处理,程序将会终止并输出错误信息。
抛出异常的作用
抛出异常是一种主动发现并报告错误的方式。当程序执行到某个条件不满足或出现错误时,开发者可以手动抛出一个异常,让调用者知道发生了什么问题,并进行相应的处理。这样可以避免程序在错误状态下继续运行,导致更严重的问题。
使用方法
抛出内置异常
在 Python 中,可以使用 raise 语句来抛出异常。raise 语句的基本语法如下:
raise ExceptionType("异常信息")
以下是一个简单的示例,当输入的数字为负数时,抛出 ValueError 异常:
def check_positive(num):
if num < 0:
raise ValueError("输入的数字不能为负数")
return num
try:
result = check_positive(-5)
except ValueError as e:
print(f"捕获到异常: {e}")
自定义异常
除了使用内置异常类型,开发者还可以自定义异常类。自定义异常类需要继承自 Python 的内置异常类,通常继承自 Exception 类。以下是一个自定义异常类的示例:
class MyCustomError(Exception):
pass
def divide_numbers(a, b):
if b == 0:
raise MyCustomError("除数不能为零")
return a / b
try:
result = divide_numbers(10, 0)
except MyCustomError as e:
print(f"捕获到自定义异常: {e}")
常见实践
在函数中抛出异常
在函数中抛出异常是一种常见的实践。当函数接收到无效的参数或无法完成其任务时,可以抛出异常,让调用者处理。例如:
def get_element(lst, index):
if index < 0 or index >= len(lst):
raise IndexError("索引超出范围")
return lst[index]
my_list = [1, 2, 3]
try:
element = get_element(my_list, 5)
except IndexError as e:
print(f"捕获到异常: {e}")
在类中抛出异常
在类的方法中也可以抛出异常。例如,当类的属性被赋予无效值时,可以抛出异常:
class Rectangle:
def __init__(self, width, height):
if width <= 0 or height <= 0:
raise ValueError("宽度和高度必须为正数")
self.width = width
self.height = height
try:
rect = Rectangle(-2, 3)
except ValueError as e:
print(f"捕获到异常: {e}")
复杂案例:
案例一:信用卡支付
class PaymentError(Exception):
"""支付异常"""
def __init__(self, amount, payment_method, error_code, *args):
self.amount = amount
self.payment_method = payment_method
self.error_code = error_code
self.details = args
# 格式化错误消息
details_str = f" - 详情: {', '.join(map(str, args))}" if args else ""
super().__init__(
f"支付失败: 金额 {amount} 元, 方式 {payment_method}, 错误码 {error_code}{details_str}"
)
def process_payment(amount, payment_method):
"""处理支付"""
if amount <= 0:
raise PaymentError(
amount,
payment_method,
"ERR001",
"支付金额必须大于0"
)
if amount > 10000 and payment_method == "credit_card":
raise PaymentError(
amount,
payment_method,
"ERR002",
"信用卡支付超过限额",
"最大限额: 10000元",
"请使用其他支付方式"
)
if payment_method not in ["credit_card", "alipay", "wechat_pay"]:
raise PaymentError(
amount,
payment_method,
"ERR003",
"不支持的支付方式",
f"支持的方式: credit_card, alipay, wechat_pay"
)
print(f"支付成功: {amount}元, 使用{payment_method}")
return True
if __name__ == "__main__":
"""演示支付异常"""
print("\n=== 支付系统演示 ===")
payments = [
(100, "credit_card"),
(0, "alipay"),
(15000, "credit_card"),
(500, "bank_transfer"),
(200, "alipay")
]
for amount, method in payments:
print(f"\n尝试支付: {amount}元, 使用{method}")
try:
process_payment(amount, method)
except PaymentError as e:
print(f"支付异常: {e}")
print(f"错误码: {e.error_code}")
print(f"详细信息: {e.details}")
except Exception as e:
print(f"其他错误: {e}")
以下是输出结果:
=== 支付系统演示 ===
尝试支付: 100元, 使用credit_card
支付成功: 100元, 使用credit_card
尝试支付: 0元, 使用alipay
支付异常: 支付失败: 金额 0 元, 方式 alipay, 错误码 ERR001 - 详情: 支付金额必须大于0
错误码: ERR001
详细信息: ('支付金额必须大于0',)
尝试支付: 15000元, 使用credit_card
支付异常: 支付失败: 金额 15000 元, 方式 credit_card, 错误码 ERR002 - 详情: 信用卡支付超过限额, 最大限额: 10000元, 请使用其他支付方式
错误码: ERR002
详细信息: ('信用卡支付超过限额', '最大限额: 10000元', '请使用其他支付方式')
尝试支付: 500元, 使用bank_transfer
支付异常: 支付失败: 金额 500 元, 方式 bank_transfer, 错误码 ERR003 - 详情: 不支持的支付方式, 支持的方式: credit_card, alipay, wechat_pay
错误码: ERR003
详细信息: ('不支持的支付方式', '支持的方式: credit_card, alipay, wechat_pay')
尝试支付: 200元, 使用alipay
支付成功: 200元, 使用alipay
案例二:用户校验
# 1. 定义自定义异常类
class InvalidUserError(Exception):
"""自定义异常:无效用户异常"""
def __init__(self, username, age, email, *args):
"""
初始化异常,接收多个参数
Args:
username: 用户名
age: 年龄
email: 邮箱
*args: 其他信息
"""
self.username = username
self.age = age
self.email = email
self.additional_info = args
# 创建错误消息
message = f"用户 '{username}' 无效 - 年龄: {age}, 邮箱: {email}"
if args:
message += f", 其他信息: {', '.join(map(str, args))}"
super().__init__(message)
# 2. 使用自定义异常的函数
def validate_user(username, age, email):
"""
验证用户信息,如果不合法则抛出异常
Args:
username: 用户名
age: 年龄
email: 邮箱
"""
errors = []
# 验证用户名
if not username or len(username) < 3:
errors.append("用户名至少需要3个字符")
# 验证年龄
if age < 0 or age > 120:
errors.append("年龄必须在0-120之间")
# 验证邮箱
if "@" not in email:
errors.append("邮箱格式不正确")
# 如果有错误,抛出自定义异常
if errors:
# 传递多个参数给异常
raise InvalidUserError(
username, # 第一个参数
age, # 第二个参数
email, # 第三个参数
f"验证失败: {errors}", # 第四个参数
len(errors) # 第五个参数
)
print(f"用户 {username} 验证通过!")
return True
# 3. 主程序 - 捕获和处理自定义异常
if __name__ == "__main__":
# 测试用例
test_cases = [
("ab", 25, "[email protected]"), # 用户名太短
("john_doe", -5, "[email protected]"), # 年龄无效
("alice", 30, "invalid-email"), # 邮箱无效
("john_doe", 25, "[email protected]"), # 有效用户
]
for username, age, email in test_cases:
print(f"\n正在验证用户: 用户名='{username}', 年龄={age}, 邮箱='{email}'")
try:
validate_user(username, age, email)
except InvalidUserError as e:
# 捕获自定义异常
print(f"捕获到自定义异常: {e}")
print(f"异常类型: {type(e).__name__}")
print(f"用户名: {e.username}")
print(f"年龄: {e.age}")
print(f"邮箱: {e.email}")
if e.additional_info:
print(f"附加信息: {e.additional_info}")
# 访问异常的所有属性
print(f"所有异常属性: {e.__dict__}")
except Exception as e:
# 捕获其他异常
print(f"捕获到其他异常: {type(e).__name__}: {e}")
以下是输出结果:
正在验证用户: 用户名='ab', 年龄=25, 邮箱='[email protected]'
捕获到自定义异常: 用户 'ab' 无效 - 年龄: 25, 邮箱: [email protected], 其他信息: 验证失败: ['用户名至少需要3个字符'], 1
异常类型: InvalidUserError
用户名: ab
年龄: 25
邮箱: [email protected]
附加信息: ("验证失败: ['用户名至少需要3个字符']", 1)
所有异常属性: {'username': 'ab', 'age': 25, 'email': '[email protected]', 'additional_info': ("验证失败: ['用户名至少需要3个字符']", 1)}
正在验证用户: 用户名='john_doe', 年龄=-5, 邮箱='[email protected]'
捕获到自定义异常: 用户 'john_doe' 无效 - 年龄: -5, 邮箱: [email protected], 其他信息: 验证失败: ['年龄必须在0-120之间'], 1
异常类型: InvalidUserError
用户名: john_doe
年龄: -5
邮箱: [email protected]
附加信息: ("验证失败: ['年龄必须在0-120之间']", 1)
所有异常属性: {'username': 'john_doe', 'age': -5, 'email': '[email protected]', 'additional_info': ("验证失败: ['年龄必须在0-120之间']", 1)}
正在验证用户: 用户名='alice', 年龄=30, 邮箱='invalid-email'
捕获到自定义异常: 用户 'alice' 无效 - 年龄: 30, 邮箱: invalid-email, 其他信息: 验证失败: ['邮箱格式不正确'], 1
异常类型: InvalidUserError
用户名: alice
年龄: 30
邮箱: invalid-email
附加信息: ("验证失败: ['邮箱格式不正确']", 1)
所有异常属性: {'username': 'alice', 'age': 30, 'email': 'invalid-email', 'additional_info': ("验证失败: ['邮箱格式不正确']", 1)}
正在验证用户: 用户名='john_doe', 年龄=25, 邮箱='[email protected]'
用户 john_doe 验证通过!
案例三:继承自定义异常
class NetworkError(Exception):
"""网络异常基类"""
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}")
class TimeoutError(NetworkError):
"""超时异常 - 继承自NetworkError"""
def __init__(self, url, timeout_seconds):
self.timeout_seconds = timeout_seconds
super().__init__(url, 408, f"请求超时 ({timeout_seconds}秒)")
class NotFoundError(NetworkError):
"""资源未找到异常 - 继承自NetworkError"""
def __init__(self, url):
super().__init__(url, 404, "资源未找到")
def fetch_data(url):
"""模拟获取数据"""
if "timeout" in url:
raise TimeoutError(url, 30)
elif "notfound" in url:
raise NotFoundError(url)
elif "servererror" in url:
raise NetworkError(url, 500, "服务器内部错误")
print(f"成功获取: {url}")
return "data"
if __name__ == "__main__":
"""演示网络异常"""
print("\n=== 网络请求演示 ===")
urls = [
"http://api.example.com/data",
"http://api.example.com/timeout",
"http://api.example.com/notfound",
"http://api.example.com/servererror"
]
for url in urls:
print(f"\n请求URL: {url}")
try:
data = fetch_data(url)
except TimeoutError as e:
print(f"超时异常: {e}")
print(f"超时时间: {e.timeout_seconds}秒")
except NotFoundError as e:
print(f"未找到异常: {e}")
print(f"状态码: {e.status_code}")
except NetworkError as e:
print(f"网络异常: {e}")
print(f"URL: {e.url}, 状态码: {e.status_code}")
except Exception as e:
print(f"其他异常: {e}")
以下是输出结果:
=== 网络请求演示 ===
请求URL: http://api.example.com/data
成功获取: http://api.example.com/data
请求URL: http://api.example.com/timeout
超时异常: 网络错误: http://api.example.com/timeout (状态码: 408) - 请求超时 (30秒)
超时时间: 30秒
请求URL: http://api.example.com/notfound
未找到异常: 网络错误: http://api.example.com/notfound (状态码: 404) - 资源未找到
状态码: 404
请求URL: http://api.example.com/servererror
网络异常: 网络错误: http://api.example.com/servererror (状态码: 500) - 服务器内部错误
URL: http://api.example.com/servererror, 状态码: 500
小结
本文详细介绍了 Python 中抛出异常的基础概念、使用方法、常见实践以及最佳实践。通过合理地抛出和处理异常,可以提高程序的健壮性和可维护性。在实际开发中,应根据具体情况选择合适的异常类型,并提供详细的异常信息。同时,要避免在不必要的地方抛出异常,以提高程序的性能。
六.全文概览
