23

我有一个字典列表,我想对其进行序列化:

list_of_dicts = [ { 'key_1': 'value_a', 'key_2': 'value_b'},
                  { 'key_1': 'value_c', 'key_2': 'value_d'},
                  ...
                  { 'key_1': 'value_x', 'key_2': 'value_y'}  ]

yaml.dump(list_of_dicts, file, default_flow_style = False)

产生以下内容:

- key_1: value_a
  key_2: value_b
- key_1: value_c
  key_2: value_d
(...)
- key_1: value_x
  key_2: value_y

但我想得到这个:

- key_1: value_a
  key_2: value_b
                     <-|
- key_1: value_c       | 
  key_2: value_d       |  empty lines between blocks
(...)                  |
                     <-|
- key_1: value_x
  key_2: value_y

PyYAML文档非常简短地讨论了dump()参数,并且似乎没有关于这个特定主题的任何内容。

手动编辑文件以添加换行符大大提高了可读性,之后结构仍然加载得很好,但我不知道如何让转储方法生成它。

一般来说,除了简单的缩进之外,有没有办法更好地控制输出格式?

4

3 回答 3

20

使用库没有简单的方法来做到这一点(yaml dumper 语法树中的节点对象是被动的,不能发出这个信息),所以我最终得到了

stream = yaml.dump(list_of_dicts, default_flow_style = False)
file.write(stream.replace('\n- ', '\n\n- '))
于 2013-05-15T09:16:54.767 回答
5

PyYAML 文档只简单地谈论dump()论点,因为没有太多要说的。PyYAML 不提供这种控制。

为了允许在加载的 YAML 中保留这些空(和注释)行,我开始开发ruamel.yaml库,它是停滞的 PyYAML 的超集,具有 YAML 1.2 兼容性,添加了许多功能并修复了错误。与ruamel.yaml您一起可以:

import sys
import ruamel.yaml

yaml_str = """\
- key_1: value_a
  key_2: value_b

- key_1: value_c
  key_2: value_d

- key_1: value_x  # a few before this were ellipsed
  key_2: value_y
"""

yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

并获得与输入字符串完全相同的输出(包括注释)。

您还可以从头开始构建所需的输出:

import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML()
list_of_dicts = yaml.seq([ { 'key_1': 'value_a', 'key_2': 'value_b'},
                           { 'key_1': 'value_c', 'key_2': 'value_d'},
                           { 'key_1': 'value_x', 'key_2': 'value_y'}  ])

for idx in range(1, len(list_of_dicts)):
    list_of_dicts.yaml_set_comment_before_after_key(idx, before='\n')

ruamel.yaml.comments.dump_comments(list_of_dicts)
yaml.dump(list_of_dicts, sys.stdout)

使用转换yaml.seq()是创建一个允许通过特殊属性附加空行的对象所必需的。

The library also allows preservation/easy-setting of quotes and literal style on strings, format of int (hex, octal, binary) and floats. As well as separate indent specification for mappings and sequences (although not for individual mappings or sequences).

于 2017-08-15T14:16:41.810 回答
3

虽然有点笨拙,但我的目标与 OP 相同。我通过子类化 yaml.Dumper 解决了它

from yaml import Dumper

class MyDumper(Dumper):

  def write_indent(self):
    indent = self.indent or 0
    if not self.indention or self.column > indent \
        or (self.column == indent and not self.whitespace):
      self.write_line_break()


    ##########$#######################################
    # On the first level of indentation, add an extra
    # newline

    if indent == 2:
      self.write_line_break()

    ##################################################

    if self.column < indent:
      self.whitespace = True
      data = u' '*(indent-self.column)
      self.column = indent
      if self.encoding:
        data = data.encode(self.encoding)
      self.stream.write(data)

你这样称呼它:

print dump(python_dict, default_flow_style=False, width=79, Dumper=MyDumper)
于 2017-05-31T12:28:04.843 回答