4

我正在使用 Ruamel Python 库以编程方式编辑人工编辑的 YAML 文件。源文件具有按字母顺序排序的键。

我不确定这是一个基本的 Python 问题,还是一个 Ruamel 问题,但是我尝试对 Ruamel 的 OrderedDict 结构进行排序的所有方法对我来说都失败了。

例如,我很困惑,为什么基于这个配方的以下代码不起作用:

import ruamel.yaml
import collections

def read_file(f):
    with open(f, 'r') as _f:
        return ruamel.yaml.round_trip_load(
            _f.read(),
            preserve_quotes=True
        )

def write_file(f, data):
    with open(f, 'w') as _f:
        _f.write(ruamel.yaml.dump(
            data,
            Dumper=ruamel.yaml.RoundTripDumper,
            explicit_start=True,
            width=1024
        ))

data = read_file('in.yaml')
data = collections.OrderedDict(sorted(data.items(), key=lambda t: t[0]))
write_file('out.yaml', data)

但是给定这个输入文件:

---
bananas: 1
apples: 2

生成以下输出文件:

--- !!omap
- apples: 2
- bananas: 1

即它把我的文件变成了一个 YAML 有序映射。

是否有捷径可寻?另外,我可以以某种方式简单地插入数据结构吗?

4

1 回答 1

5

如果您在ruamel.yaml¹ 中往返映射,则映射不会表示为 a collections.OrderedDict(),而是表示为 a ruamel.yaml.comments.CommentedMap()。后者可以是collections.OrderedDict()取决于您正在使用的 Python 版本的子类(例如,在 Python 2 中,它使用来自 的更快的 C 实现ruamel.ordereddict

在 round_trip_dump 模式下,表示器不会自动将“正常”有序字典(无论是 fromcollections还是)解释为特殊字典。ruamel.ordereddict但如果你放弃collections

import ruamel.yaml

def read_file(f):
    with open(f, 'r') as _f:
        return ruamel.yaml.round_trip_load(
            _f.read(),
            preserve_quotes=True
        )

def write_file(f, data):
    with open(f, 'w') as _f:
        ruamel.yaml.dump(
            data,
            stream=_f,
            Dumper=ruamel.yaml.RoundTripDumper,
            explicit_start=True,
            width=1024
        )

data = read_file('in.yaml')
data = ruamel.yaml.comments.CommentedMap(sorted(data.items(), key=lambda t: t[0]))
write_file('out.yaml', data)

你的out.yaml意愿是:

---
apples: 2
bananas: 1

请注意,我还删除了您write_file日常工作中的低效率。如果您不指定流,则所有数据将首先流式传输到StringIO实例(在内存中)然后返回(您将其写入流中_f.write(),直接写入流效率更高。

至于您的最后一个问题:是的,您可以使用以下方法插入:

data.insert(1, 'apricot', 3)

¹免责声明:我是ruamel.yamlruamel.ordereddict的作者。

于 2016-09-03T15:02:57.220 回答