# 【主流程 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) # 对于其他类型,调用父类默认方法