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)