背景
日常开发过程中经常碰到dict转object的场景,如何灵活优雅的转换?这里提供一种基于 dataclasses 装饰器的方式。
例子
from dataclasses import dataclass, asdict, is_dataclass
@dataclass
class UpdateProgressRecord(object):
""" 更新进度记录 """ # 更新时间
update_time: str = ''
# 更新文件的md5
update_file_md5: str = ''
# 更新的 Id 列表
ids: list[int] = None
# 是否完成整个文件的整体更新
is_finished: bool = False
# 更新的开始行数
start_idx_include: int = 0
# 更新的结束行数
end_idx_exclude: int = 0
# 更新的向量数
updated_count: int = 0
value = {'ids':[1,2,3], 'update_count': 2}
# dict 转 object
update_record = UpdateProgressRecord(**value)
进阶
在实践中发现在序列化 UpdateProgressRecord 对象的时候出错,json.dumps 不支持 @dataclass 装饰的对象。通过自定义encoder解决,代码如下:
class EnhancedJSONEncoder(json.JSONEncoder):
""" dataclasses json encoder """
def default(self, o): # pylint: disable=E0202
""" as dict """
if is_dataclass(o):
return asdict(o)
return super().default(o)
完整代码如下:
class EnhancedJSONEncoder(json.JSONEncoder):
""" dataclasses json encoder """
def default(self, o): # pylint: disable=E0202
""" as dict """
if is_dataclass(o):
return asdict(o)
return super().default(o)
@dataclass
class UpdateProgressRecord(object):
""" 更新进度记录 """ # 更新时间
update_time: str = ''
# 更新文件的md5
update_file_md5: str = ''
# 更新的 Id 列表
ids: list[int] = None
# 是否完成整个文件的整体更新
is_finished: bool = False
# 更新的开始行数
start_idx_include: int = 0
# 更新的结束行数
end_idx_exclude: int = 0
# 更新的向量数
updated_count: int = 0
value = {'ids':[1,2,3], 'update_count': 2}
# dict 转 object
update_record = UpdateProgressRecord(**value)
json.dumps(update_record, cls=EnhancedJSONEncoder, ensure_ascii=False)
干预dataclass更多进阶的内容可以学习:Data Classes in Python 3.7+ (Guide) – Real Python