Python Formatter类
Python中Formatter类是string模块中的一个重要类,实现了Python字符串格式化的底层机制,允许创建自定义的格式化。
基础概念
Formatter类是Python标准库中string模块的核心组件,提供了字符串格式化的基础框架。该类实现了format()方法的底层逻辑,通过继承和重写相关方法来实现自定义的格式化行为。Formatter类的设计遵循了开放封闭原则,既提供了默认的格式化功能,又允许用户根据特定需求进行扩展。
Formatter类的主要职责包括解析格式化字符串、处理字段替换、应用格式规范以及生成最终的格式化结果。通过一系列可重写的方法,如get_field()、get_value()、check_unused_args()等,为开发者提供了精细控制格式化过程的能力。
核心方法
1、基本使用方法
Formatter类的最基本用法是直接实例化并调用format方法。这个方法接受格式化字符串作为第一个参数,后续参数用于填充格式化占位符。
import string # 创建Formatter实例并进行基本格式化 formatter = string.Formatter() result = formatter.format("你好, {name}! 你的年龄是 {age}.", name="Alice", age=25) print(result) # 使用位置参数进行格式化 result2 = formatter.format("名字{0} 年龄{1} 爱好{2}.", "Alice", "25", "游戏") print(result2)
2、自定义Formatter类
通过继承Formatter类并重写相关方法,可以创建具有特定行为的自定义格式化器。
import string from datetime import datetime class CustomFormatter(string.Formatter): def get_value(self, key, args, kwargs): # 自定义获取值的逻辑 if isinstance(key, str): try: # 尝试从kwargs中获取值 return kwargs[key] except KeyError: # 如果键不存在,返回默认值 return f"[{key} not found]" else: # 处理位置参数 return super().get_value(key, args, kwargs) def format_field(self, value, format_spec): # 自定义字段格式化逻辑 if format_spec == 'upper': return str(value).upper() elif format_spec == 'datetime': if isinstance(value, datetime): return value.strftime('%Y-%m-%d %H:%M:%S') return super().format_field(value, format_spec) # 使用自定义Formatter custom_formatter = CustomFormatter() result = custom_formatter.format("Name: {name:upper}, Time: {time:datetime}", name="john doe", time=datetime.now()) print(result) # 测试缺失键的处理 result2 = custom_formatter.format("Hello {name}, your score is {score}", name="Alice") print(result2)
高级应用场景
1、安全格式化实现
在处理用户输入或不可信数据时,安全的字符串格式化变得尤为重要。通过自定义Formatter类,可以实现对格式化过程的严格控制,防止潜在的安全风险。
import string class SafeFormatter(string.Formatter): def __init__(self, allowed_keys=None): super().__init__() self.allowed_keys = set(allowed_keys) if allowed_keys else set() def get_value(self, key, args, kwargs): # 只允许访问预定义的键 if isinstance(key, str) and key not in self.allowed_keys: raise ValueError(f"Access to key '{key}' is not allowed") return super().get_value(key, args, kwargs) def get_field(self, field_name, args, kwargs): # 禁止访问属性和方法 if '.' in field_name or '[' in field_name: raise ValueError("Attribute access and indexing are not allowed") return super().get_field(field_name, args, kwargs) # 使用安全格式化器 safe_formatter = SafeFormatter(allowed_keys=['username', 'message']) try: # 正常使用 result = safe_formatter.format("User: {username}, Message: {message}", username="alice", message="Hello World") print(result) # 尝试访问不允许的键 result2 = safe_formatter.format("Secret: {password}", password="secret123") except ValueError as e: print(f"安全错误: {e}")
2、条件格式化器
在某些应用场景中,需要根据数据的值或类型来决定格式化的方式。通过创建条件格式化器,可以实现智能的格式化行为,根据不同的条件应用不同的格式化规则。
import string class ConditionalFormatter(string.Formatter): def format_field(self, value, format_spec): # 处理数值的条件格式化 if format_spec.startswith('cond:'): conditions = format_spec[5:].split('|') for condition in conditions: if ':' in condition: test, format_rule = condition.split(':', 1) if self._evaluate_condition(value, test): return self._apply_format(value, format_rule) return str(value) # 默认返回字符串形式 return super().format_field(value, format_spec) def _evaluate_condition(self, value, test): # 简单的条件评估 if test.startswith('>'): return float(value) > float(test[1:]) elif test.startswith('<'): return float(value) < float(test[1:]) elif test.startswith('='): return str(value) == test[1:] return False def _apply_format(self, value, format_rule): # 应用格式规则 if format_rule == 'currency': return f"${float(value):.2f}" elif format_rule == 'percent': return f"{float(value):.1%}" elif format_rule.startswith('prefix:'): prefix = format_rule[7:] return f"{prefix}{value}" return str(value) # 使用条件格式化器 cond_formatter = ConditionalFormatter() # 测试不同条件下的格式化 values = [1500, 50, 0.25] for value in values: result = cond_formatter.format( "Value: {amount:cond:>1000:currency|>0:prefix:+|=0:prefix:zero}", amount=value ) print(result)
实际应用案例
1、日志格式化系统
在实际的软件开发中,日志格式化是Formatter类的重要应用场景。通过自定义Formatter,可以创建统一的日志格式化系统,确保日志信息的一致性和可读性。
import string from datetime import datetime class LogFormatter(string.Formatter): def __init__(self): super().__init__() self.log_levels = { 'DEBUG': '🐛', 'INFO': 'ℹ️', 'WARNING': '⚠️', 'ERROR': '❌', 'CRITICAL': '🚨' } def format_field(self, value, format_spec): if format_spec == 'level_icon': return self.log_levels.get(str(value), '❓') elif format_spec == 'timestamp': if isinstance(value, datetime): return value.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] elif format_spec == 'module_short': # 缩短模块名称 return str(value).split('.')[-1] if '.' in str(value) else str(value) return super().format_field(value, format_spec) # 使用日志格式化器 log_formatter = LogFormatter() log_template = "{timestamp:timestamp} [{level:level_icon}] {module:module_short}: {message}" # 模拟日志条目 log_entries = [ {'timestamp': datetime.now(), 'level': 'INFO', 'module': 'app.main', 'message': 'Application started'}, {'timestamp': datetime.now(), 'level': 'WARNING', 'module': 'app.database', 'message': 'Connection timeout'}, {'timestamp': datetime.now(), 'level': 'ERROR', 'module': 'app.api.user', 'message': 'User not found'} ] for entry in log_entries: formatted_log = log_formatter.format(log_template, **entry) print(formatted_log)
2、API响应格式化器
通过自定义Formatter类,创建统一的API响应格式化系统,确保不同接口返回数据的一致性和规范性。
import string from datetime import datetime import json class APIResponseFormatter(string.Formatter): def __init__(self): super().__init__() self.status_messages = { 200: 'Success', 400: 'Bad Request', 401: 'Unauthorized', 404: 'Not Found', 500: 'Internal Server Error' } def format_field(self, value, format_spec): if format_spec == 'status_text': return self.status_messages.get(int(value), 'Unknown Status') elif format_spec == 'iso_time': if isinstance(value, datetime): return value.isoformat() elif format_spec == 'json_data': return json.dumps(value, ensure_ascii=False, indent=2) elif format_spec == 'success_flag': return str(int(value) < 400).lower() return super().format_field(value, format_spec) # 使用API响应格式化器 api_formatter = APIResponseFormatter() response_template = '''{{ "status": {status}, "status_text": "{status:status_text}", "success": {status:success_flag}, "timestamp": "{timestamp:iso_time}", "data": {data:json_data}, "message": "{message}" }}''' # 模拟不同的API响应 responses = [ { 'status': 200, 'timestamp': datetime.now(), 'data': {'user_id': 123, 'username': 'alice', 'email': 'alice@example.com'}, 'message': 'User retrieved successfully' }, { 'status': 404, 'timestamp': datetime.now(), 'data': None, 'message': 'User not found' }, { 'status': 500, 'timestamp': datetime.now(), 'data': {'error_code': 'DB_CONNECTION_FAILED'}, 'message': 'Database connection failed' } ] for response in responses: formatted_response = api_formatter.format(response_template, **response) print(formatted_response) print("-" * 50)