python - 如何在 PyYaml 中处理标签/类的向后兼容性?
问题描述
假设我有一个类MyClass
驻留在 package 中my_package
。将此类数据转储到 YAML 可能会产生:
!!python/object:my_package.MyClass
my_field_1: "foo"
my_field_2: "bar"
这些数据可以用默认加载器反序列化就好了。但是我们如何处理重构包/类名呢?例如,如果我们将包重命名为my_new_package
,则代码无法像预期的那样反序列化现有的 YAML 文件:
yaml.constructor.ConstructorError: while constructing a Python object
cannot find 'MyClass' in the module 'my_package'
如何向 YAML 加载程序添加向后兼容性,以便仍然可以加载旧数据?
我的第一次尝试是自定义加载器并注册旧标签名称以实现向后兼容性:
class CustomLoader(yaml.SafeLoader):
pass
def my_class_loader(loader, node):
# to be implemented
CustomLoader.add_constructor("!!python/object:my_package.MyClass", my_class_loader)
data = yaml.load(f, Loader=CustomLoader)
不幸的是,PyYaml 从未调用此自定义加载。是否有另一种方法可以将旧标签注入到加载过程中?
解决方案
我找到了一个可行的解决方案,但我不确定这是否是解决它的最优雅的方法:
看起来 PyYaml在执行构造函数查找之前在内部将存储的标签!!python/object:my_package.MyClass
转换为。tag:yaml.org,2002:python/object:my_package.MyClass
因此,为了为旧标签名称注册一个自定义加载器,可以执行以下操作:
# Example class
class MyClass(object):
def __init__(my_field_1, my_field_2):
self.my_field_1 = my_field_1
self.my_field_2 = my_field_2
@staticmethod
def from_dict(d):
return MyClass(
my_field_1=d["my_field_1"],
my_field_2=d["my_field_2"],
)
# Build a custom loader
class CustomLoader(yaml.SafeLoader):
pass
def my_class_loader(loader, node):
mapping = loader.construct_mapping(node)
return MyClass.from_dict(mapping)
# Register the old tag name
CustomLoader.add_constructor(
"tag:yaml.org,2002:python/object:my_package.MyClass",
my_class_loader)
# Load using custom loader
data = yaml.load(f, Loader=CustomLoader)
推荐阅读
- javascript - 如何从由斜杠分隔的 url 中获取 url 参数,例如 http://myweb.com/example/12345/222/4444 我想从上面的 url 中获取 12345、222、4444
- java - tomcat 7 到 9 迁移:java.lang.IllegalArgumentException:指定的主资源集 [...] 无效
- javascript - 引导日期时间选择器未打开
- magento - magento 2.3 安装后黑屏
- python - 从 Music21 保存图像文件
- swift - 如何将来自uiimageView的图像存储在firebase中
- ios - 如何在 Swift 的注释视图上显示不同的图标?
- javascript - 调用 google API json 文件并将其显示为 html,未检索到数据但成功调用站点
- reactjs - 与 haul 不工作的本地反应,引发一些 loader 问题
- javascript - 下拉链接未显示在 HTML 表格中