Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 格式化PyYAML dump()输出_Python_Yaml_Pyyaml - Fatal编程技术网

Python 格式化PyYAML dump()输出

Python 格式化PyYAML dump()输出,python,yaml,pyyaml,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, fi

我有一个要序列化的词典列表:

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
-键1:值
键2:值

对于库,没有简单的方法可以做到这一点(yaml转储程序语法树中的节点对象是被动的,不能发出此信息),因此我最终使用了

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

虽然有点糟糕,但我的目标和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)

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

为了在加载的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格式(十六进制、八进制、二进制)和浮点。以及映射和序列的单独缩进规范(尽管不适用于单个映射或序列)。

谢谢!必须使用类似的格式设置列表。PyYAML没有将缩进放在
-
之前,而YAML使用我们使用的库时希望在那里有一些缩进。因此,我们必须执行
replace('-','-')
节点是被动的,这是正确的,但与此无关,因为节点也不发出任何其他信息(即
ScalarNode
s不发出它们自己的值)。
Emitter
确实会获取节点的值(在适当的时候)并发射它,如果您在节点上附加额外的信息,并增强相关的发射器方法来处理这些额外的信息(就像我在
ruamel.yaml
中所做的那样),那么绝对没有必要这样做,基于字符串的后处理。@Andrei和您一起可以设置
yaml.indent(sequence=3,offset=1)
并在不进行后处理的情况下获得该输出。回答得好,为您自己改进的yaml解析器干杯,我现在就来试试,因为我自己正在研究转储格式问题。但我突然想到,自从这篇文章发表以来,Pyaml一直在不断更新。从那以后,他们的格式改进了吗?或者你的贡献被并入Pyaml了?两个问题都没有。我所知道的唯一真正的机会是,如果对输入没有100%的控制,PyYAML的
load()
就不再那么危险。它仍然是YAML 1.1,多个长期存在的bug仍然没有修复。更改似乎主要是为了与较新版本的Python兼容。我认为我的(和所有其他PRs)是随着从bitbucket迁移到github而被删除的(这项工作最好花在修复PyYAML IMHO的bug上)。ruamel.yaml现在可以选择在项目指示器(
-
)后面控制一个额外的换行符:
.compact\u seq\u seq
resp
.compact\u seq\u map
受此启发,我创建了另一个版本
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)