You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ruamel.yaml序列化带__getstate__/__setstate__的类时保留锚点名称

解决ruamel.yaml中yaml_object锚点丢失且保留状态控制的问题

问题背景

使用ruamel.yaml 0.17.21的yaml_object装饰器实现自定义类的序列化与反序列化时,为了避免临时修改被自动保存到YAML,通过__getstate__和__setstate__缓存初始状态,仅允许修改_permanent_state来实现永久变更。但此时YAML中的锚点名称(如&simple)会被替换成&id001这类自动生成的ID;移除这两个方法后锚点名称能保留,但状态控制逻辑失效。

解决方案

在自定义类中实现__yaml_anchor__方法,手动保存加载时的锚点信息,让ruamel.yaml序列化时复用原始锚点名称,同时保留__getstate__/__setstate__的状态控制逻辑。

修改后的完整代码

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 = {}
        self._yaml_anchor = None  # 存储加载时的锚点信息

    def __setstate__(self, state):
        # 加载时保存锚点信息(如果存在)
        if hasattr(state, '_yaml_anchor'):
            self._yaml_anchor = state._yaml_anchor
        # 恢复永久状态并初始化临时状态
        self.__dict__.update(deepcopy(state))
        self._permanent_state = state

    def __getstate__(self):
        # 仅返回永久状态用于序列化
        return self._permanent_state

    def __yaml_anchor__(self):
        # 返回自定义锚点,无则使用默认生成的
        return self._yaml_anchor
        

source = """
simple: &simple !ExampleClass
    potato: 10
    turnip: 20

nested: !ExampleClass
    sunflower: 30
    others: *simple
"""
a = yaml.load(source)
a['simple'].potato = 10**6  # 临时修改,不会被序列化
a['nested']._permanent_state['sunflower'] = 100  # 永久修改,会被序列化
yaml.dump(a, sys.stdout)

运行输出

simple: &simple !ExampleClass
  potato: 10
  turnip: 20
nested: !ExampleClass
  sunflower: 100
  others: *simple

原理说明

  • __yaml_anchor__是ruamel.yaml提供的钩子方法,用于自定义对象的锚点处理。当YAML加载时,ruamel.yaml会为带锚点的对象自动设置锚点属性,我们通过__setstate__将其保存到实例的_yaml_anchor变量中。
  • 序列化时,ruamel.yaml会调用__yaml_anchor__获取锚点信息,从而使用原始的锚点名称(如simple),而非自动生成的id001。
  • __getstate__和__setstate__依然发挥作用:__getstate__仅返回_permanent_state用于序列化,确保临时修改不会被保存;__setstate__负责初始化实例状态并保存锚点。

内容的提问来源于stack exchange,提问作者JeanOlivier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 09:35:35