backup materials and knowledge-base docs
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
"""
|
||||
错误处理模式示例
|
||||
|
||||
展示各种错误处理的最佳实践
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional, List, Dict, Any
|
||||
from functools import wraps
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# ============================================
|
||||
# 模式 1:具体异常捕获
|
||||
# ============================================
|
||||
|
||||
def read_file(filepath: str) -> Optional[str]:
|
||||
"""
|
||||
捕获具体异常而不是宽泛的 Exception
|
||||
"""
|
||||
try:
|
||||
with open(filepath, 'r') as f:
|
||||
return f.read()
|
||||
except FileNotFoundError:
|
||||
logger.error(f"文件不存在: {filepath}")
|
||||
return None
|
||||
except PermissionError:
|
||||
logger.error(f"没有权限读取文件: {filepath}")
|
||||
return None
|
||||
except UnicodeDecodeError:
|
||||
logger.error(f"文件编码错误: {filepath}")
|
||||
return None
|
||||
|
||||
|
||||
# ============================================
|
||||
# 模式 2:带重试的操作
|
||||
# ============================================
|
||||
|
||||
def retry_operation(max_attempts: int = 3):
|
||||
"""
|
||||
装饰器:自动重试失败的操作
|
||||
"""
|
||||
def decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
for attempt in range(1, max_attempts + 1):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
if attempt == max_attempts:
|
||||
logger.error(f"操作失败,已重试 {max_attempts} 次: {e}")
|
||||
raise
|
||||
logger.warning(f"操作失败,第 {attempt} 次重试...")
|
||||
return None
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
@retry_operation(max_attempts=3)
|
||||
def unstable_api_call() -> Dict[str, Any]:
|
||||
"""
|
||||
模拟不稳定的 API 调用
|
||||
"""
|
||||
import random
|
||||
if random.random() < 0.7: # 70% 失败率
|
||||
raise ConnectionError("API 连接失败")
|
||||
return {"status": "success", "data": "result"}
|
||||
|
||||
|
||||
# ============================================
|
||||
# 模式 3:上下文管理器处理资源
|
||||
# ============================================
|
||||
|
||||
class DatabaseConnection:
|
||||
"""
|
||||
自定义上下文管理器,确保资源正确释放
|
||||
"""
|
||||
def __init__(self, connection_string: str):
|
||||
self.connection_string = connection_string
|
||||
self.connection = None
|
||||
|
||||
def __enter__(self):
|
||||
logger.info(f"连接数据库: {self.connection_string}")
|
||||
self.connection = f"Connection to {self.connection_string}"
|
||||
return self.connection
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
if exc_type is not None:
|
||||
logger.error(f"发生异常: {exc_val}")
|
||||
logger.info("关闭数据库连接")
|
||||
# 清理资源
|
||||
self.connection = None
|
||||
return False # 不抑制异常
|
||||
|
||||
|
||||
# ============================================
|
||||
# 模式 4:链式异常(保留原始异常)
|
||||
# ============================================
|
||||
|
||||
def validate_and_process(data: Dict[str, Any]) -> Any:
|
||||
"""
|
||||
使用 raise from 保留原始异常链
|
||||
"""
|
||||
try:
|
||||
# 验证数据
|
||||
if 'value' not in data:
|
||||
raise ValueError("数据中缺少 'value' 字段")
|
||||
|
||||
value = data['value']
|
||||
if not isinstance(value, (int, float)):
|
||||
raise TypeError(f"value 应该是数字,实际类型: {type(value)}")
|
||||
|
||||
# 处理数据
|
||||
return value * 2
|
||||
|
||||
except (ValueError, TypeError) as e:
|
||||
# 保留原始异常并添加上下文
|
||||
raise RuntimeError(f"数据处理失败: {data}") from e
|
||||
|
||||
|
||||
# ============================================
|
||||
# 模式 5:结果对象模式(不使用异常)
|
||||
# ============================================
|
||||
|
||||
class Result:
|
||||
"""
|
||||
结果对象模式:封装成功/失败状态
|
||||
"""
|
||||
def __init__(self, success: bool, value: Any = None, error: str = None):
|
||||
self.success = success
|
||||
self.value = value
|
||||
self.error = error
|
||||
|
||||
@classmethod
|
||||
def ok(cls, value: Any) -> 'Result':
|
||||
return cls(success=True, value=value)
|
||||
|
||||
@classmethod
|
||||
def err(cls, error: str) -> 'Result':
|
||||
return cls(success=False, error=error)
|
||||
|
||||
def is_ok(self) -> bool:
|
||||
return self.success
|
||||
|
||||
def is_err(self) -> bool:
|
||||
return not self.success
|
||||
|
||||
def unwrap(self) -> Any:
|
||||
if not self.success:
|
||||
raise ValueError(f"尝试解包错误结果: {self.error}")
|
||||
return self.value
|
||||
|
||||
def unwrap_or(self, default: Any) -> Any:
|
||||
return self.value if self.success else default
|
||||
|
||||
|
||||
def safe_divide_result(a: float, b: float) -> Result:
|
||||
"""
|
||||
使用结果对象而不是异常
|
||||
"""
|
||||
if b == 0:
|
||||
return Result.err(f"除数不能为零: {b}")
|
||||
|
||||
try:
|
||||
return Result.ok(a / b)
|
||||
except Exception as e:
|
||||
return Result.err(f"计算失败: {e}")
|
||||
|
||||
|
||||
# ============================================
|
||||
# 模式 6:多项验证错误收集
|
||||
# ============================================
|
||||
|
||||
class ValidationError(Exception):
|
||||
"""自定义验证错误"""
|
||||
def __init__(self, errors: List[str]):
|
||||
self.errors = errors
|
||||
super().__init__("\n".join(errors))
|
||||
|
||||
|
||||
def validate_user(data: Dict[str, Any]) -> None:
|
||||
"""
|
||||
收集所有验证错误而不是遇到第一个就停止
|
||||
"""
|
||||
errors = []
|
||||
|
||||
if 'name' not in data:
|
||||
errors.append("缺少 'name' 字段")
|
||||
elif not isinstance(data['name'], str):
|
||||
errors.append("'name' 应该是字符串")
|
||||
elif len(data['name']) < 2:
|
||||
errors.append("'name' 长度应该至少为 2")
|
||||
|
||||
if 'age' not in data:
|
||||
errors.append("缺少 'age' 字段")
|
||||
elif not isinstance(data['age'], int):
|
||||
errors.append("'age' 应该是整数")
|
||||
elif data['age'] < 0 or data['age'] > 150:
|
||||
errors.append("'age' 应该在 0-150 之间")
|
||||
|
||||
if 'email' in data and '@' not in data['email']:
|
||||
errors.append("'email' 格式不正确")
|
||||
|
||||
if errors:
|
||||
raise ValidationError(errors)
|
||||
|
||||
|
||||
# ============================================
|
||||
# 模式 7:默认值和回退
|
||||
# ============================================
|
||||
|
||||
def get_config(config: Dict[str, Any], key: str, default: Any = None) -> Any:
|
||||
"""
|
||||
安全获取配置,支持多级键和默认值
|
||||
"""
|
||||
if '.' in key:
|
||||
# 支持嵌套键,如 "database.host"
|
||||
keys = key.split('.')
|
||||
value = config
|
||||
for k in keys:
|
||||
if isinstance(value, dict) and k in value:
|
||||
value = value[k]
|
||||
else:
|
||||
return default
|
||||
return value
|
||||
|
||||
# 简单键
|
||||
return config.get(key, default)
|
||||
|
||||
|
||||
# ============================================
|
||||
# 模式 8:优雅降级
|
||||
# ============================================
|
||||
|
||||
def get_user_preferences(user_id: int) -> Dict[str, Any]:
|
||||
"""
|
||||
尝试多种方法获取用户偏好,优雅降级
|
||||
"""
|
||||
# 尝试 1:从缓存获取
|
||||
try:
|
||||
return _get_from_cache(user_id)
|
||||
except Exception as e:
|
||||
logger.warning(f"从缓存获取失败: {e}")
|
||||
|
||||
# 尝试 2:从数据库获取
|
||||
try:
|
||||
return _get_from_database(user_id)
|
||||
except Exception as e:
|
||||
logger.warning(f"从数据库获取失败: {e}")
|
||||
|
||||
# 尝试 3:使用默认配置
|
||||
logger.info("使用默认配置")
|
||||
return _get_default_preferences()
|
||||
|
||||
|
||||
def _get_from_cache(user_id: int) -> Dict[str, Any]:
|
||||
# 模拟缓存失败
|
||||
raise ConnectionError("缓存连接失败")
|
||||
|
||||
|
||||
def _get_from_database(user_id: int) -> Dict[str, Any]:
|
||||
# 模拟数据库失败
|
||||
raise ConnectionError("数据库连接失败")
|
||||
|
||||
|
||||
def _get_default_preferences() -> Dict[str, Any]:
|
||||
return {
|
||||
"theme": "light",
|
||||
"language": "zh-CN",
|
||||
"notifications": True
|
||||
}
|
||||
|
||||
|
||||
# ============================================
|
||||
# 测试代码
|
||||
# ============================================
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
print("=" * 50)
|
||||
print("错误处理模式示例")
|
||||
print("=" * 50)
|
||||
|
||||
# 测试结果对象模式
|
||||
print("\n1. 结果对象模式:")
|
||||
result1 = safe_divide_result(10, 2)
|
||||
print(f"10 / 2 = {result1.unwrap()}")
|
||||
|
||||
result2 = safe_divide_result(10, 0)
|
||||
print(f"10 / 0 = {result2.unwrap_or('N/A')} ({result2.error})")
|
||||
|
||||
# 测试优雅降级
|
||||
print("\n2. 优雅降级:")
|
||||
prefs = get_user_preferences(123)
|
||||
print(f"用户偏好: {prefs}")
|
||||
|
||||
# 测试上下文管理器
|
||||
print("\n3. 上下文管理器:")
|
||||
try:
|
||||
with DatabaseConnection("localhost:5432") as conn:
|
||||
print(f"连接: {conn}")
|
||||
except Exception as e:
|
||||
print(f"操作失败: {e}")
|
||||
Reference in New Issue
Block a user