我设置了使用ruamel加载/转储的类。yaml 0.17.21yaml_object
decorator.
出于某种原因,我不希望类中的更改保存到yaml,除非用户特别要求。为了做到这一点,我使用__getstate__
和__setstate__
方法来缓存initial_state,并且如果用户想要永久更改,则指示用户修改该对象。
一切正常,除了在转储时丢失锚的名称。我无法准确地指出它是如何。当没有定义__{set|get}state__
方法时,yaml通常保留这些方法。
这些易于阅读的锚名对我来说非常重要,因为它是一个用户友好的功能。
下面是一个例子:
import sys
from copy import deepcopy
from ruamel.yaml import YAML, yaml_object
yaml = YAML()
@yaml_object(yaml)
class ExampleClass():
def __init__(self):
self._permanent_state = {}
def __setstate__(self, state):
self.__dict__.update(deepcopy(state))
self._permanent_state = state
def __getstate__(self):
return self._permanent_state
source = """
simple: &simple !ExampleClass
potato: 10
turnip: 20
nested: !ExampleClass
sunflower: 30
others: *simple
"""
a = yaml.load(source)
a['simple'].potato = 10**6 # Should not be reflected in dump
a['nested']._permanent_state['sunflower'] = 100 # Should be reflected in dump
yaml.dump(a, sys.stdout)
输出simple
锚重命名为id001
:
simple: &id001 !ExampleClass
potato: 10
turnip: 20
nested: !ExampleClass
sunflower: 100
others: *id001
如果我删除__getstate__
和__setstate__
方法
import sys
from copy import deepcopy
from ruamel.yaml import YAML, yaml_object
yaml = YAML()
@yaml_object(yaml)
class ExampleClass():
pass
source = """
simple: &simple !ExampleClass
potato: 10
turnip: 20
nested: !ExampleClass
sunflower: 30
others: *simple
"""
a = yaml.load(source)
a['simple'].potato = 10**6 # Should not be reflected in dump
a['nested']._permanent_state = deepcopy(a['nested'].__dict__)
a['nested']._permanent_state['sunflower'] = 100 # Should not be reflected in dump
yaml.dump(a, sys.stdout)
输出现在保留simple
锚(但期望的行为丢失):
simple: &simple !ExampleClass
potato: 1000000
turnip: 20
nested: !ExampleClass
sunflower: 30
others: *simple
_permanent_state:
sunflower: 100
others: !ExampleClass
potato: 1000000
turnip: 20
理想情况下,我希望保持第一个示例的行为,同时保留锚名称。
如果您没有提供反例,我就会猜测锚点不会保留在任何已注册类的实例上。
__setstate__
的存在强制在构造函数中使用不同的执行路径,其中锚信息不会主动删除,但只是不使用。很可能子类化(并使用)RoundTripConstructor
和RoundTripRepresenter
来存储/检索节点中可用的锚信息。同样地,你也会丢失那些"属于"的注释。你的标记映射。
加载YAML文档可能最简单的方法是不注册ExampleClass
,然后递归地遍历加载的数据,寻找"dict"(子类)具有.tag
属性(实际上是一个属性)设置为!ExcampleClass
的实例,并将其替换为适当行为的实例(或可能添加您想要的特定行为,使用duck-typing)。