格式化PyYAML dump()输出

时间:2013-01-09 05:40:51

标签: python yaml pyyaml

我有一个字典列表,我想序列化:

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 documentation非常简短地谈论dump()个论点,似乎没有任何关于这个特定主题的内容。

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

总的来说,除了简单的缩进之外,还有一种方法可以更好地控制输出格式吗?

3 个答案:

答案 0 :(得分:15)

使用库没有简单的方法(yaml dumper语法树中的Node对象是被动的,无法发出此信息),所以我最终得到了

stream = yaml.dump(list_of_dicts, default_flow_style = False)
file.write(stream.replace('\n- ', '\n\n- '))

答案 1 :(得分:2)

PyYAML文档仅简要讨论dump()个参数,因为没有太多可说的。 PyYAML不提供这种控制。

为了保留加载的YAML中的这些空(和注释)行,我开始开发ruamel.yaml库,停滞的PyYAML的超集,兼容YAML 1.2,添加了许多功能和bug固定。使用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()进行转换是创建允许通过特殊属性附加空行的对象所必需的。

该库还允许保留/轻松设置字符串上的引号和文字样式,int(十六进制,八进制,二进制)和浮点数的格式。以及映射和序列的单独缩进规范(尽管不是针对单个映射或序列)。

答案 2 :(得分:0)

虽然它有点笨拙,但我的目标与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)