Python嵌套类YAML存读异常:类路径识别错误的解决办法问询
嵌套Dataclass的YAML序列化/反序列化修复方案
你遇到的问题是PyYAML默认无法正确识别嵌套类的完整路径,导致序列化后生成的类标识缺失外层类信息,反序列化时找不到对应类。以下是无需逐个类加装饰器的解决办法:
问题本质
PyYAML默认用{类.__module__}.{类.__name__}生成对象的类型标签,但嵌套类的__name__只有自身名称(比如Data),不会带上外层类Hello,所以标签变成了python/object:hello.Data,而实际正确的路径应该是hello.Hello.Data。
解决方案:自定义YAML的表示器和构造器
通过全局注册自定义逻辑,让PyYAML使用类的__qualname__(保存完整嵌套路径的属性)来生成标签,同时反序列化时根据完整路径定位类。
完整实现代码
# hello.py import pydantic as dan import yaml import importlib class Hello: @dan.dataclasses.dataclass class Data: data_a: int # 自定义序列化逻辑:用__qualname__生成完整类路径 def serialize_nested_class(dumper, obj): full_class_path = f"{obj.__class__.__module__}.{obj.__class__.__qualname__}" return dumper.represent_mapping(f'python/object:{full_class_path}', obj.__dict__) # 自定义反序列化逻辑:根据完整路径查找嵌套类 def deserialize_nested_class(loader, node): # 从标签中提取完整类路径 full_class_path = node.tag.split(':')[-1] # 拆分模块名和完整类名(比如"hello.Hello.Data"拆成("hello", "Hello.Data")) module_name, nested_class_path = full_class_path.rsplit('.', 1) # 拆分外层类和嵌套类(比如"Hello.Data"拆成("Hello", "Data")) outer_class_name, inner_class_name = nested_class_path.rsplit('.', 1) # 导入模块并获取外层类,再获取嵌套类 module = importlib.import_module(module_name) outer_class = getattr(module, outer_class_name) target_class = getattr(outer_class, inner_class_name) # 构造并返回对象 return target_class(**loader.construct_mapping(node)) # 全局注册:所有对象都用这个逻辑处理(可根据需求限制为dataclass) yaml.add_multi_representer(object, serialize_nested_class) yaml.add_multi_constructor('python/object:', deserialize_nested_class) # 测试代码 data = Hello.Data(1) filename = "hi.yaml" with open(filename, "w") as fh: yaml.dump(data, fh) # 现在生成的标签是python/object:hello.Hello.Data with open(filename, "r") as fh: loaded_data = yaml.load(fh, yaml.Loader) print(loaded_data) # 输出:Data(data_a=1) print(type(loaded_data)) # 输出:<class '__main__.Hello.Data'>
可选优化:仅针对Dataclass处理
如果不想全局修改所有对象的序列化逻辑,可以只针对pydantic的dataclass注册:
# 替换全局注册的代码 from pydantic.dataclasses import Dataclass yaml.add_multi_representer(Dataclass, serialize_nested_class) yaml.add_multi_constructor('python/object:', deserialize_nested_class)
关键说明
__qualname__是Python类的内置属性,会保留类的完整嵌套结构(比如Hello.Data),结合模块名就能生成唯一的类标识。- 自定义构造器通过拆分路径逐层查找类,确保能正确定位嵌套类,无需额外装饰每个类。
内容的提问来源于stack exchange,提问作者Inyoung Kim 김인영
相关产品推荐
相关产品推荐

