ruamel.yaml 支持 none 和 null

ruamel.yaml support for both none & null

我有一个 YAML 文件如下

输入:

a:
  test: null
  test12:

预期输出:(输入无变化)

a:
  test: null
  test12:

下面是我的代码

import ruamel.yaml


def my_represent_none(self, data):
    return self.represent_scalar(u'tag:yaml.org,2002:null', u'')

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.allow_duplicate_keys = True
yaml.default_flow_style = None
yaml.representer.ignore_aliases = lambda *data: True
yaml.representer.add_representer(type(None), my_represent_none)

但是,这会导致 test: null 更改为 test: 这不应该发生,并且输入值不应该有任何更改。

我怎样才能做到这一点?

首先,输入值没有变化。是否 Null Language-Independent Type 是 表示为 ~nullNullNull 或空字符串, 值始终相同。

你想要的输出是通用的,因为你有两个值要加载 in Python as None 两者通常以相同的方式表示。相反 例如字符串标量,其中可以通过子类化 str 来保留信息引号 有有用的实例可以使用,你不能继承 None 并期望典型的 if data['a']['test'] is None: 按预期工作。所以没有保存 YAML 中 Null 类型的实际值,输出标准化为 1 和 相同的值。

但是如果第一个 Null 类型需要表示为 null 并且所有 其他作为空字符串(如您预期的输出),您可以这样做:

import sys
import ruamel.yaml

yaml_str = """\
a:
  test: null
  test12:
"""

class NullRepresenter:
    def __init__(self):
        self.count = 0

    def __call__(self, repr, data):
         ret_val = repr.represent_scalar(u'tag:yaml.org,2002:null', 
                  u'null' if self.count == 0 else u'')
         self.count += 1
         return ret_val

my_represent_none = NullRepresenter()

yaml = ruamel.yaml.YAML()
yaml.representer.add_representer(type(None), my_represent_none)

yaml.dump(yaml.load(yaml_str), sys.stdout)

给出:

a:
  test: null
  test12:

假设你可以,在加载期间标记所有的实际表示 空类型并存储它们(使用 NullRepresenter 的一些额外方法) 并在倾倒时取回它们。然而,这将是不平凡的 如果具有 None 值的 keys/elements 的数量或顺序发生变化, 或上下文发生变化,例如空字符串不能再用作表示。

In Python None 是同一个对象,在您的数据结构中使用的任何地方。 表示不一致是没有意义的,而且是 可能会混淆 YAML 文档的人为解释。