本文目录导读:

我来分享一个Python工具类封装的完整案例,包含通用设计模式和最佳实践。
基础工具类设计
import os
import json
import yaml
import logging
import hashlib
from datetime import datetime
from typing import Any, Dict, List, Optional, Union
from pathlib import Path
class BaseTool:
"""工具基类,提供通用功能"""
def __init__(self, config: Optional[Dict] = None):
self.config = config or {}
self.logger = self._setup_logger()
def _setup_logger(self) -> logging.Logger:
"""配置日志器"""
logger = logging.getLogger(self.__class__.__name__)
logger.setLevel(logging.INFO)
if not logger.handlers:
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
def validate_config(self, required_keys: List[str]) -> bool:
"""验证配置完整性"""
missing_keys = [k for k in required_keys if k not in self.config]
if missing_keys:
self.logger.warning(f"Missing config keys: {missing_keys}")
return False
return True
class FileUtils(BaseTool):
"""文件操作工具类"""
def __init__(self, config: Optional[Dict] = None):
super().__init__(config)
self.supported_extensions = config.get('extensions', ['.txt', '.json', '.csv'])
def read_file(self, file_path: str, encoding: str = 'utf-8') -> str:
"""读取文件内容"""
try:
with open(file_path, 'r', encoding=encoding) as f:
return f.read()
except FileNotFoundError:
self.logger.error(f"File not found: {file_path}")
raise
except Exception as e:
self.logger.error(f"Error reading file: {e}")
raise
def write_file(self, file_path: str, content: str, mode: str = 'w') -> bool:
"""写入文件"""
try:
os.makedirs(os.path.dirname(file_path) or '.', exist_ok=True)
with open(file_path, mode, encoding='utf-8') as f:
f.write(content)
self.logger.info(f"File written successfully: {file_path}")
return True
except Exception as e:
self.logger.error(f"Error writing file: {e}")
return False
def json_reader(self, file_path: str) -> Dict:
"""读取JSON文件"""
content = self.read_file(file_path)
return json.loads(content)
def json_writer(self, file_path: str, data: Any, indent: int = 2) -> bool:
"""写入JSON文件"""
content = json.dumps(data, indent=indent, ensure_ascii=False)
return self.write_file(file_path, content)
def get_file_info(self, file_path: str) -> Dict:
"""获取文件信息"""
path = Path(file_path)
if not path.exists():
return {}
return {
'name': path.name,
'extension': path.suffix,
'size': path.stat().st_size,
'modified_time': datetime.fromtimestamp(path.stat().st_mtime).isoformat(),
'absolute_path': str(path.absolute())
}
class DataTransformer(BaseTool):
"""数据转换工具类"""
@staticmethod
def to_json(data: Any) -> str:
"""转换为JSON字符串"""
return json.dumps(data, ensure_ascii=False, default=str)
@staticmethod
def from_json(json_str: str) -> Any:
"""从JSON字符串转换"""
return json.loads(json_str)
@staticmethod
def to_yaml(data: Any) -> str:
"""转换为YAML字符串"""
return yaml.dump(data, default_flow_style=False, allow_unicode=True)
@staticmethod
def from_yaml(yaml_str: str) -> Any:
"""从YAML字符串转换"""
return yaml.safe_load(yaml_str)
def transform_list(self, data: List, operation: str, **kwargs) -> List:
"""列表转换操作"""
operations = {
'flatten': self._flatten_list,
'unique': lambda x: list(set(x)),
'sort': lambda x: sorted(x, **kwargs),
'filter': lambda x: [i for i in x if i not in kwargs.get('exclude', [])]
}
if operation in operations:
return operations[operation](data)
else:
self.logger.error(f"Unknown operation: {operation}")
return data
@staticmethod
def _flatten_list(nested_list: List) -> List:
"""展平嵌套列表"""
result = []
for item in nested_list:
if isinstance(item, list):
result.extend(DataTransformer._flatten_list(item))
else:
result.append(item)
return result
class SecurityUtils(BaseTool):
"""安全工具类"""
@staticmethod
def hash_password(password: str, salt: str = '') -> str:
"""密码哈希"""
combined = password + salt
return hashlib.sha256(combined.encode()).hexdigest()
@staticmethod
def md5_hash(text: str) -> str:
"""MD5哈希"""
return hashlib.md5(text.encode()).hexdigest()
@staticmethod
def generate_token(length: int = 32) -> str:
"""生成随机令牌"""
import secrets
return secrets.token_hex(length // 2)
def sanitize_filename(self, filename: str) -> str:
"""清理文件名,移除不安全字符"""
import re
# 移除非字母数字和.-_的字符
sanitized = re.sub(r'[^\w\.\-]', '_', filename)
# 限制长度
max_length = self.config.get('max_filename_length', 255)
return sanitized[:max_length]
class APIClient(BaseTool):
"""API客户端工具类"""
def __init__(self, config: Optional[Dict] = None):
super().__init__(config)
self.base_url = config.get('base_url', '')
self.timeout = config.get('timeout', 30)
self.retry_count = config.get('retry_count', 3)
def get(self, endpoint: str, params: Optional[Dict] = None) -> Dict:
"""GET请求"""
import requests
url = f"{self.base_url}/{endpoint.lstrip('/')}"
for attempt in range(self.retry_count):
try:
response = requests.get(url, params=params, timeout=self.timeout)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
self.logger.error(f"Request failed (attempt {attempt + 1}): {e}")
if attempt == self.retry_count - 1:
raise
def post(self, endpoint: str, data: Dict) -> Dict:
"""POST请求"""
import requests
url = f"{self.base_url}/{endpoint.lstrip('/')}"
try:
response = requests.post(url, json=data, timeout=self.timeout)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
self.logger.error(f"POST request failed: {e}")
raise
高级工具类模式
class CacheUtils(BaseTool):
"""缓存工具类,支持多级缓存"""
def __init__(self, config: Optional[Dict] = None):
super().__init__(config)
self.cache = {}
self.cache_type = config.get('cache_type', 'memory')
self.max_size = config.get('max_cache_size', 100)
if self.cache_type == 'file':
self.cache_dir = Path(config.get('cache_dir', './cache'))
self.cache_dir.mkdir(exist_ok=True)
def get(self, key: str) -> Any:
"""获取缓存"""
if self.cache_type == 'memory':
return self.cache.get(key)
else:
return self._get_file_cache(key)
def set(self, key: str, value: Any, ttl: int = 3600) -> None:
"""设置缓存"""
if self.cache_type == 'memory':
self._set_memory_cache(key, value)
else:
self._set_file_cache(key, value)
self.logger.debug(f"Cache set for key: {key}")
def _set_memory_cache(self, key: str, value: Any) -> None:
"""内存缓存管理"""
if len(self.cache) >= self.max_size:
# LRU淘汰策略
self.cache.pop(next(iter(self.cache)))
self.cache[key] = value
def _get_file_cache(self, key: str) -> Optional[Any]:
"""文件缓存读取"""
cache_file = self.cache_dir / f"{hashlib.md5(key.encode()).hexdigest()}.json"
if cache_file.exists():
with open(cache_file, 'r') as f:
return json.load(f)
return None
def _set_file_cache(self, key: str, value: Any) -> None:
"""文件缓存写入"""
cache_file = self.cache_dir / f"{hashlib.md5(key.encode()).hexdigest()}.json"
with open(cache_file, 'w') as f:
json.dump(value, f)
def clear(self) -> None:
"""清空缓存"""
self.cache.clear()
self.logger.info("Cache cleared")
class ValidatorUtils(BaseTool):
"""数据验证工具类"""
@staticmethod
def validate_email(email: str) -> bool:
"""验证邮箱格式"""
import re
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email))
@staticmethod
def validate_phone(phone: str) -> bool:
"""验证手机号格式"""
import re
pattern = r'^1[3-9]\d{9}$'
return bool(re.match(pattern, phone))
@staticmethod
def validate_url(url: str) -> bool:
"""验证URL格式"""
from urllib.parse import urlparse
try:
result = urlparse(url)
return all([result.scheme, result.netloc])
except:
return False
def validate_json_schema(self, data: Dict, schema: Dict) -> bool:
"""JSON Schema验证"""
try:
import jsonschema
jsonschema.validate(instance=data, schema=schema)
return True
except jsonschema.exceptions.ValidationError as e:
self.logger.error(f"Validation error: {e}")
return False
使用示例
def main():
"""使用示例"""
# 1. 文件工具使用
file_tool = FileUtils({
'extensions': ['.txt', '.json', '.csv', '.yaml']
})
# 写入文件
file_tool.write_file('config.json', '{"name": "test"}')
# 读取JSON
config = file_tool.json_reader('config.json')
print(f"Config: {config}")
# 2. 数据转换
transformer = DataTransformer()
nested_list = [1, [2, 3], [4, [5, 6]]]
flat_list = transformer.transform_list(nested_list, 'flatten')
print(f"Flattened: {flat_list}")
# 3. 安全工具
security = SecurityUtils()
password_hash = security.hash_password("my_password", "unique_salt")
token = security.generate_token()
print(f"Token: {token}")
# 4. 缓存使用
cache = CacheUtils({
'cache_type': 'memory',
'max_cache_size': 50
})
cache.set('user_42', {'name': 'Alice', 'age': 30})
user = cache.get('user_42')
print(f"Cached user: {user}")
# 5. 验证器使用
validator = ValidatorUtils()
email = "test@example.com"
print(f"Email valid: {validator.validate_email(email)}")
if __name__ == "__main__":
main()
最佳实践总结
设计原则
- 单一职责:每个工具类只负责一个功能领域
- 开闭原则:通过继承或配置扩展功能,不改动原有代码
- 依赖注入:通过配置参数控制行为
代码规范
- 使用类型注解提供更好的代码文档
- 添加适当的日志记录便于调试
- 提供异常处理机制
- 编写完整的文档字符串
扩展建议
- 添加单元测试覆盖核心功能
- 使用装饰器实现功能增强(如重试、缓存等)
- 考虑异步版本的工具类
- 实现插件机制支持自定义扩展
这样的工具类设计既保持灵活性,又提供了统一的调用接口,便于团队协作和代码维护。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播