| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
- # 【主流程 8.3 的辅助转换】MCP 数据库查询结果含有日期、时间或 Decimal 时调用。
- # 先在查询方法中用 default_encoder 逐字段转换,再由 json.dumps/DateEncoder 完成序列化。
- """
- 需求:实现数据格式化工具,处理日期、时间和数值类型的序列化
- 思路步骤:
- 1. 导入必要的模块和库
- 2. 实现default_encoder函数(格式化单个对象)
- 3. 创建DateEncoder类(自定义JSON编码器,处理非标准类型序列化)
- 4. 重写DateEncoder.default方法(处理序列化时的默认对象转换)
- """
- import json
- from datetime import date, datetime, timedelta
- from decimal import Decimal
- def default_encoder(obj): # 定义编码器方法,用于格式化单个对象
- # 【转换内部步骤 1】datetime 是 date 的子类,先判断 datetime 才能保留时分秒。
- # 这些判断是互斥返回分支:命中一种类型就 return,不会继续依次转换所有类型。
- # 输入 obj 是某一列值,不是整条结果列表;输出是转换后的单个值。
- # 日期对象用 strftime 格式化,时间差用 str,Decimal 用 float;普通 JSON 可处理的值原样返回。
- if isinstance(obj, datetime): # 检查是否为datetime,返回带时间的格式化字符串
- # %Y/%m/%d 分别是年/月/日,%H/%M/%S 是时/分/秒;格式化结果是字符串。
- return obj.strftime('%Y-%m-%d %H:%M:%S')
- if isinstance(obj, date): # 检查是否为date,返回日期格式化字符串
- return obj.strftime('%Y-%m-%d')
- if isinstance(obj, timedelta): # 检查是否为timedelta,转换为字符串
- return str(obj)
- if isinstance(obj, Decimal): # 检查是否为Decimal,转换为浮点数
- # TODO 更优的方案 str(obj)
- return float(obj)
- return obj # 否则返回原对象
- # 定义自定义JSON编码器类,继承自json.JSONEncoder,用于处理非标准类型序列化
- class DateEncoder(json.JSONEncoder):
- def default(self, obj): # 重写default方法,处理序列化时的默认对象转换
- # 【转换内部步骤 2】json.dumps 遇到默认无法编码的对象时才回调此方法。
- # 仍不支持的类型交给父类报错;Decimal 当前转为 float,可能损失精度。
- # 此类继承 json.JSONEncoder;传给 json.dumps(cls=DateEncoder) 后,框架才会按需调用 default。
- # super().default(obj) 保留父类对未知类型的报错行为,避免静默把无法编码的值变成不明确内容。
- if isinstance(obj, (date, datetime)): # 检查对象是否为date或datetime类型,对于datetime返回带时间的字符串,对于date返回日期字符串
- return obj.strftime('%Y-%m-%d %H:%M:%S') if isinstance(obj, datetime) else obj.strftime('%Y-%m-%d')
- if isinstance(obj, timedelta): # 检查对象是否为timedelta类型,将时间差转换为字符串
- return str(obj)
- if isinstance(obj, Decimal): # 检查对象是否为Decimal类型,将Decimal转换为浮点数以兼容JSON
- return float(obj)
- return super().default(obj) # 对于其他类型,调用父类默认方法
|