【问题标题】:Copy aliases to separate Python objects when loading YAML with ruamel.yaml使用 ruamel.yaml 加载 YAML 时复制别名以分隔 Python 对象
【发布时间】:2020-12-24 05:28:50
【问题描述】:

使用 ruamel.yaml 加载 YAML 数据时,YAML 文件中的锚点及其别名在 Python 中是同一个对象:

from ruamel.yaml import YAML

yaml_str = """\
first: &reference [1, 2, 3]
second: *reference
"""

yaml = YAML()
data = yaml.load(yaml_str)

assert(data['first'] is data['second'])
# passes

data['first'].append(4)
print(data['second'])
# output: [1, 2, 3, 4]

我意识到这是一个有意的功能。但是,有没有办法告诉load 在找到别名时改为 copy 别名?我尝试按照this answer 中的说明覆盖yaml.representer.ignore_aliases,但这只是为了写入YAML,而不是从中读取。

【问题讨论】:

    标签: python yaml ruamel.yaml


    【解决方案1】:

    没有内置功能可以做你想做的事。任何时候遇到 一个别名,你必须在作曲家递归地创建一个节点结构,而不是仅仅返回别名的锚节点。

    YAML 文档中对锚点和别名的需求源于需要能够 表示递归数据结构:

    a = [1, 2]
    a.append(a)
    

    无法使用您链接到的答案中显示的技术转储上述结构,也不能将表示作为 YAML 文档而不进行扩展:

    &id001
    - 1
    - 2
    - *id001
    

    在加载过程中使用第一段中建议的技术进行扩展。

    您的(非递归)示例可以使用链接答案中的技术转储, 也可以在加载时展开。

    除非您想深入了解 ruamel.yaml,否则最简单的解决方案是 加载你的 YAML 文档,扩展转储,然后加载转储的结果:

    import sys
    import ruamel.yaml
    
    yaml_str = """\
    first: &reference [1, 2, 3]
    second: *reference
    """
    
    yaml = ruamel.yaml.YAML()
    yaml.representer.ignore_aliases = lambda *data: True
    data = yaml.load(yaml_str)
    buf = ruamel.yaml.compat.BytesIO()
    out = yaml.dump(data, buf)
    data = yaml.load(buf.getvalue())
    
    
    assert(data['first'] is not data['second'])
    assert(data['first'] == data['second'])
    
    data['first'].append(4)
    assert len(data['first']) == 4
    assert len(data['second']) == 3
    

    当然,当你有一个很大的文件时,这不是很有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-08
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 2020-05-30
      • 2017-04-26
      相关资源
      最近更新 更多