在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用。下面我将详细解释主动抛出异常的各种用法和场景。
主动抛出异常(也称为"引发异常")的主要目的是:
使用raise
关键字可以主动抛出异常:
异常类型可以自己定义,通过class定义。
raise 异常类型(错误信息)
def divide(a, b):
if b == 0:
# ValueError是内置的异常类型,就不需要自己定义了
raise ValueError("除数不能为零")
return a / b
try:
result = divide(10, 0)
except ValueError as e:
print(f"捕获到错误: {e}")
def get_element(lst, index):
if index >= len(lst):
# IndexError错误类型因为他原本就有所以不用class定义
raise IndexError("索引超出列表范围")
return lst[index]
# 使用
try:
get_element([1, 2, 3], 5)
except IndexError as e:
print(e) # 输出:索引超出列表范围
在except块中,可以使用不带参数的raise重新抛出当前异常:
try:
10 / 0
except ZeroDivisionError:
print("发生了除以零错误,记录日志后重新抛出")
raise # 重新抛出相同的异常
Python 3引入了异常链的概念,可以使用from
关键字:
def process_file(filename):
try:
with open(filename) as f:
return f.read()
except IOError as e:
raise RuntimeError("文件处理失败") from e
try:
process_file("nonexistent.txt")
except RuntimeError as e:
print(f"主错误: {e}")
print(f"原始原因: {e.__cause__}") # 访问原始异常
我们经常需要定义自己的 **异常类型 **来更好地表达特定的错误情况:
# 自定义一个异常类型(InvalidEmailError),以及异常消息
class InvalidEmailError(Exception):
"""当电子邮件格式无效时抛出"""
pass
def send_email(email):
if "@" not in email:
raise InvalidEmailError(f"无效的邮箱地址: {email}")
# 发送邮件逻辑...
try:
send_email("userexample.com") # 缺少@符号
except InvalidEmailError as e:
print(f"邮件发送失败: {e}")
class TemperatureError(Exception):
def __init__(self, temp, min_temp, max_temp):
self.temp = temp
self.min_temp = min_temp
self.max_temp = max_temp
super().__init__(f"温度{temp}超出范围({min_temp}-{max_temp})")
def check_temperature(temp):
if not (0 <= temp <= 100):
raise TemperatureError(temp, 0, 100)
print("温度正常")
try:
check_temperature(-5)
except TemperatureError as e:
print(f"错误温度: {e.temp}, 允许范围: {e.min_temp}-{e.max_temp}")
def process_age(age):
if not isinstance(age, int):
raise TypeError("年龄必须是整数")
if age < 0:
raise ValueError("年龄不能为负数")
if age < 18:
print("未成年人")
else:
print("成年人")
# 测试
for age in [15, 25, -3, "20"]:
try:
process_age(age)
except (TypeError, ValueError) as e:
print(f"无效输入: {e}")
特性 | raise | assert |
---|---|---|
目的 | 主动引发异常 | 用于调试,检查不应为假的条件 |
生产环境 | 应该使用 | 通常不应使用(可能被-O禁用) |
语法 | raise 异常类型("消息") |
assert 条件, "消息" |
引发异常 | 任何异常类型 | 总是AssertionError |
适用场景 | 处理预期的错误情况 | 检查程序内部一致性 |
def calculate_average(numbers):
assert len(numbers) > 0, "数字列表不能为空"
return sum(numbers) / len(numbers)
# 等同于
def calculate_average(numbers):
if len(numbers) == 0:
raise ValueError("数字列表不能为空")
return sum(numbers) / len(numbers)
def create_user(username, email):
if not username:
raise ValueError("用户名不能为空")
if len(username) < 3:
raise ValueError("用户名至少需要3个字符")
if "@" not in email:
raise ValueError("无效的邮箱格式")
print(f"创建用户: {username}, 邮箱: {email}")
try:
create_user("ab", "invalid-email")
except ValueError as e:
print(f"用户创建失败: {e}")
class DatabaseError(Exception):
pass
class ConnectionError(DatabaseError):
pass
class QueryError(DatabaseError):
pass
def execute_query(query):
if not query.startswith("SELECT"):
raise QueryError("只支持SELECT查询")
# 模拟连接失败
if "fail" in query:
raise ConnectionError("数据库连接失败")
print(f"执行查询: {query}")
queries = ["SELECT * FROM users", "UPDATE users", "SELECT fail"]
for query in queries:
try:
execute_query(query)
except ConnectionError as e:
print(f"连接问题: {e}")
except QueryError as e:
print(f"查询错误: {e}")
主动抛出异常是Python编程中的强大工具,它可以帮助我们:
记住原则:当函数无法完成其宣称的功能时,应该抛出异常。通过合理使用raise,你可以写出更专业、更可靠的Python代码!