一、什么是 raise?
raise 是 Python 中用于手动抛出异常的关键字。当程序检测到错误条件时,可以使用 raise 主动触发异常,中断正常的程序流程。
二、raise 的基本用法
1. 抛出内置异常
def basic_raise(): """raise 的基本用法""" # 1. 抛出异常实例 try: raise ValueError("这是一个值错误") except ValueError as e: print(f"捕获到异常: {e}") # 2. 抛出异常类(会自动创建实例) try: raise ValueError except ValueError as e: print(f"捕获到异常类: {e}") # 3. 抛出异常时不带参数 try: raise ValueError() except ValueError as e: print(f"捕获到空异常: {e}") # 4. 重新抛出当前异常 try: try: raise TypeError("类型错误") except TypeError: print("重新抛出异常") raise # 重新抛出 except TypeError as e: print(f"最终捕获: {e}")basic_raise()
2. 抛出带参数的异常
def raise_with_args(): """抛出带参数的异常""" # 单个参数 try: raise ValueError("错误信息") except ValueError as e: print(f"错误信息: {e}") # 多个参数(某些异常支持) try: raise RuntimeError("错误信息", "额外信息", 123) except RuntimeError as e: print(f"多个参数: {e.args}") print(f"第一个参数: {e.args[0]}") print(f"第二个参数: {e.args[1]}") # 使用关键字参数 try: raise ValueError(message="自定义消息", code=500) except ValueError as e: print(f"消息: {e}") # 注意:ValueError 不支持直接访问关键字参数raise_with_args()
三、自定义异常
1. 创建自定义异常类
def custom_exception_classes(): """自定义异常类""" # 基础自定义异常 class MyError(Exception): """我的自定义异常""" pass # 带字段的自定义异常 class ValidationError(Exception): def __init__(self, field, message, code=None): self.field = field self.message = message self.code = code super().__init__(f"{field}: {message}") # 带方法的自定义异常 class BusinessError(Exception): def __init__(self, message, severity="error"): self.message = message self.severity = severity self.timestamp = None def with_timestamp(self): from datetime import datetime self.timestamp = datetime.now() return self def __str__(self): return f"[{self.severity.upper()}] {self.message}" # 使用自定义异常 try: raise MyError("这是一个自定义异常") except MyError as e: print(f"自定义异常: {e}") try: raise ValidationError("email", "邮箱格式不正确", code=1001) except ValidationError as e: print(f"验证错误: {e}") print(f"字段: {e.field}, 代码: {e.code}") try: error = BusinessError("业务逻辑错误", "critical").with_timestamp() raise error except BusinessError as e: print(f"业务错误: {e}") print(f"严重级别: {e.severity}") print(f"时间戳: {e.timestamp}")custom_exception_classes()
2. 异常层次结构
def exception_hierarchy(): """异常层次结构""" # 定义异常层次 class AppError(Exception): """应用基础异常""" pass class ConfigError(AppError): """配置错误""" pass class DatabaseError(AppError): """数据库错误""" pass class ConnectionError(DatabaseError): """连接错误""" pass class QueryError(DatabaseError): """查询错误""" pass class ValidationError(AppError): """验证错误""" pass def process_data(): """处理数据的函数""" # 可以抛出不同级别的异常 import random error_type = random.choice(['config', 'connection', 'query', 'validation']) if error_type == 'config': raise ConfigError("配置文件格式错误") elif error_type == 'connection': raise ConnectionError("无法连接到数据库") elif error_type == 'query': raise QueryError("SQL 语法错误") else: raise ValidationError("数据验证失败") # 处理异常 try: process_data() except ConnectionError as e: print(f"连接错误(具体): {e}") except DatabaseError as e: print(f"数据库错误(一般): {e}") except AppError as e: print(f"应用错误: {e}") except Exception as e: print(f"其他错误: {e}")exception_hierarchy()
四、raise 的高级用法
1. 异常链 (raise ... from)
def exception_chaining(): """异常链 - raise ... from""" def parse_config(filename): """解析配置文件""" try: with open(filename, 'r') as f: return eval(f.read()) except FileNotFoundError as e: # 抛出新的异常,保留原始异常 raise RuntimeError(f"配置文件 {filename} 不存在") from e except SyntaxError as e: # 抛出新的异常,保留原始异常 raise RuntimeError(f"配置文件语法错误") from e def load_settings(): """加载设置""" try: config = parse_config("config.txt") return config except RuntimeError as e: # 访问原始异常 print(f"错误: {e}") print(f"原始错误: {e.__cause__}") raise # 使用异常链 try: load_settings() except RuntimeError as e: print(f"\n最终捕获: {e}") print(f"原因: {e.__cause__}") # 抑制原始异常 (from None) def process_without_chain(): try: result = 10 / 0 except ZeroDivisionError: raise ValueError("计算错误") from None try: process_without_chain() except ValueError as e: print(f"\n抑制原始异常: {e}") print(f"原始异常: {e.__cause__}") # Noneexception_chaining()
2. 条件性抛出
def conditional_raise(): """条件性抛出异常""" def validate_age(age): """验证年龄""" if not isinstance(age, int): raise TypeError(f"年龄必须是整数,得到 {type(age).__name__}") if age < 0: raise ValueError(f"年龄不能为负数: {age}") if age > 150: raise ValueError(f"年龄超出合理范围: {age}") return True # 批量验证 ages = [25, -5, "三十", 200, 18] for age in ages: try: validate_age(age) print(f"✓ {age} 验证通过") except TypeError as e: print(f"✗ {age}: 类型错误 - {e}") except ValueError as e: print(f"✗ {age}: 值错误 - {e}")conditional_raise()
3. 在循环中使用 raise
def raise_in_loop(): """在循环中使用 raise""" def process_items(items): """处理项目列表""" results = [] for i, item in enumerate(items): try: # 模拟处理逻辑 if item is None: raise ValueError(f"项目 {i} 为 None") if not isinstance(item, (int, float)): raise TypeError(f"项目 {i} 不是数字") if item == 0: raise ZeroDivisionError(f"项目 {i} 为 0") result = 100 / item results.append(result) except (ValueError, TypeError, ZeroDivisionError) as e: print(f"跳过项目 {i}: {e}") continue return results # 测试 test_data = [10, None, "abc", 0, 5, 2] results = process_items(test_data) print(f"处理结果: {results}")raise_in_loop()
五、raise 的最佳实践
1. 异常设计原则
def design_principles(): """异常设计原则""" # 1. 异常应该有意义 class UserNotFoundError(Exception): """用户不存在""" pass class UserAlreadyExistsError(Exception): """用户已存在""" pass # 2. 提供有用的错误信息 def find_user(user_id): if user_id <= 0: raise ValueError(f"无效的用户ID: {user_id}") # ... # 3. 使用合适的异常类型 def divide(a, b): if b == 0: raise ZeroDivisionError("除数不能为0") # 使用内置异常 return a / b # 4. 不要滥用异常 def bad_use(data, index): try: return data[index] except IndexError: return None # 应该使用条件判断 def good_use(data, index): if 0 <= index < len(data): return data[index] return None # 5. 文档化异常 def calculate_price(quantity, price): """ 计算总价 Args: quantity: 数量 price: 单价 Returns: 总价 Raises: ValueError: 当数量或价格为负数时 TypeError: 当参数不是数字时 """ if quantity < 0 or price < 0: raise ValueError("数量和价格不能为负数") return quantity * price print("异常设计原则演示完成")design_principles()
2. 异常处理模板
def exception_templates(): """异常处理模板""" # 模板1: 简单验证 def validate_input(value): if not value: raise ValueError("输入不能为空") return value # 模板2: 重试模式 def retry_operation(func, max_retries=3, delay=1): for attempt in range(max_retries): try: return func() except Exception as e: if attempt == max_retries - 1: raise print(f"重试 {attempt + 1}/{max_retries}: {e}") time.sleep(delay) # 模板3: 资源管理 class Resource: def __enter__(self): # 获取资源 return self def __exit__(self, exc_type, exc_val, exc_tb): # 释放资源 if exc_type: print(f"发生异常: {exc_type.__name__}") return False # 模板4: 异常转换 def convert_exception(func): from functools import wraps @wraps(func) def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except ValueError as e: raise RuntimeError(f"转换后的错误: {e}") from e return wrapper # 模板5: 日志记录 import logging def log_exception(func): @wraps(func) def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: logging.error(f"函数 {func.__name__} 失败: {e}", exc_info=True) raise return wrapper print("异常处理模板演示完成")exception_templates()
六、总结
raise 用法速查表
| | |
|---|
| raise ValueError("消息") | |
| raise ValueError | |
| raise | |
| raise NewError from e | |
| raise NewError from None | |
最佳实践总结
使用有意义的异常类型
使用内置异常或自定义异常
不要抛出 Exception 基类
提供清晰的错误信息
不要吞掉异常
除非有充分的理由,否则不要忽略异常
记录或重新抛出异常
合理使用异常链
使用 from 保留原始异常
使用 from None 隐藏实现细节
文档化异常
性能考虑
raise 是 Python 中主动抛出异常的关键工具。通过合理使用 raise,可以创建健壮、可维护的程序,清晰地表达错误条件,并提供有用的错误信息。