8

我正在尝试将 Python dict 转储到使用ruamel.yaml. 我熟悉json模块的界面,漂亮地打印字典就像

import json
with open('outfile.json', 'w') as f:
    json.dump(mydict, f, indent=4, sort_keys=True)

ruamel.yaml我已经做到了

import ruamel.yaml
with open('outfile.yaml', 'w') as f:
    ruamel.yaml.round_trip_dump(mydict, f, indent=2)

但它似乎不支持该sort_keys选项。ruamel.yaml似乎也没有任何详尽的文档,并且在 Google 中搜索“ruamel.yaml sort”或“ruamel.yaml alphabetize”并没有达到我所期望的简单程度。

是否有一个或两个行来漂亮地打印带有排序键的 YAML 文件?

(请注意,我需要在整个容器中递归地按字母顺序排列键;仅按字母顺序排列顶层是不够的。)


请注意,如果我使用round_trip_dump,则键未排序;如果我使用safe_dump,则输出不是“YAML 风格”(或更重要的是“Kubernetes 风格”)YAML。我不想[]{}在我的输出中。

$ pip freeze | grep yaml
ruamel.yaml==0.12.5

$ python
>>> import ruamel.yaml
>>> mydict = {'a':1, 'b':[2,3,4], 'c':{'a':1,'b':2}}
>>> print ruamel.yaml.round_trip_dump(mydict)  # right format, wrong sorting
a: 1
c:
  a: 1
  b: 2
b:
- 2
- 3
- 4

>>> print ruamel.yaml.safe_dump(mydict)  # wrong format, right sorting
a: 1
b: [2, 3, 4]
c: {a: 1, b: 2}
4

3 回答 3

7

您需要一些处理映射/字典、序列/列表的递归函数:

import sys
import ruamel.yaml

CM = ruamel.yaml.comments.CommentedMap

yaml = ruamel.yaml.YAML()

data = dict(a=1, c=dict(b=2, a=1), b=[2, dict(e=6, d=5), 4])
yaml.dump(data, sys.stdout)

def rec_sort(d):
    try:
        if isinstance(d, CM):
            return d.sort()
    except AttributeError:
        pass
    if isinstance(d, dict):
        # could use dict in newer python versions
        res = ruamel.yaml.CommentedMap()
        for k in sorted(d.keys()):
            res[k] = rec_sort(d[k])
        return res
    if isinstance(d, list):
        for idx, elem in enumerate(d):
            d[idx] = rec_sort(elem)
    return d

print('---')

yaml.dump(rec_sort(data), sys.stdout)

这使:

a: 1
c:
  b: 2
  a: 1
b:
- 2
- e: 6
  d: 5
- 4
---
a: 1
b:
- 2
- d: 5
  e: 6
- 4
c:
  a: 1
  b: 2

注释的映射是 ruamel.yaml 在进行往返(加载+转储)时使用的结构,往返旨在保持键在加载期间的顺序。

当您data从注释的 YAML 文件加载时,上述内容应该可以合理地保留对映射/序列的注释

于 2016-10-24T21:05:12.343 回答
0

ruamel.yaml 中有一个未记录的文件sort()可以解决这个问题的变体:

import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML()

test = """- name: a11
  value: 11
- name: a2
  value: 2
- name: a21
  value: 21
- name: a3
  value: 3
- name: a1
  value: 1"""
test_yml = yaml.load(test)

yaml.dump(test_yml, sys.stdout)

未排序的输出

  - name: a11
    value: 11
  - name: a2
    value: 2
  - name: a21
    value: 21
  - name: a3
    value: 3
  - name: a1
    value: 1

按名称分类

test_yml.sort(lambda x: x['name'])
yaml.dump(test_yml, sys.stdout)

排序输出

  - name: a1
    value: 1
  - name: a11
    value: 11
  - name: a2
    value: 2
  - name: a21
    value: 21
  - name: a3
    value: 3
于 2020-10-14T18:55:04.020 回答
0

正如@Anthon 的示例中所指出的,如果您使用的是 Python 3.7 或更新版本(并且不需要支持较低版本),您只需要:

import sys
from ruamel.yaml import YAML

yaml = YAML()

data = dict(a=1, c=dict(b=2, a=1), b=[2, dict(e=6, d=5), 4])

def rec_sort(d):
    if isinstance(d, dict):
        res = dict()
        for k in sorted(d.keys()):
            res[k] = rec_sort(d[k])
        return res
    if isinstance(d, list):
        for idx, elem in enumerate(d):
            d[idx] = rec_sort(elem)
    return d

yaml.dump(rec_sort(data), sys.stdout)

dict那个版本开始订购。

于 2021-10-04T09:33:38.600 回答