python yaml.dump坏缩进

时间:2014-08-03 20:00:44

标签: python yaml indentation

我正在执行以下python代码:

import yaml


foo = {
    'name': 'foo',
    'my_list': [{'foo': 'test', 'bar': 'test2'}, {'foo': 'test3', 'bar': 'test4'}],
    'hello': 'world'
}

print(yaml.dump(foo, default_flow_style=False))

但正在打印:

hello: world
my_list:
- bar: test2
  foo: test
- bar: test4
  foo: test3
name: foo

而不是:

hello: world
my_list:
  - bar: test2
    foo: test
  - bar: test4
    foo: test3
name: foo

如何以这种方式缩进my_list元素?

3 个答案:

答案 0 :(得分:23)

This ticket建议当前实施正确遵循the spec

  

用于表示块集合条目的“ - ”,“?”和“:”字符被人们认为是缩进的一部分。这是由相关作品逐案处理的。

在同一个主题上,还有this code snippet(已修改以适合您的示例)以获取您要查找的行为:

import yaml

class MyDumper(yaml.Dumper):

    def increase_indent(self, flow=False, indentless=False):
        return super(MyDumper, self).increase_indent(flow, False)

foo = {
    'name': 'foo',
    'my_list': [
        {'foo': 'test', 'bar': 'test2'},
        {'foo': 'test3', 'bar': 'test4'}],
    'hello': 'world',
}

print yaml.dump(foo, Dumper=MyDumper, default_flow_style=False)

答案 1 :(得分:2)

如果有帮助,我写了一些代码来处理同样的问题。只需将yaml.dump()的原始输出传递给_fix_dump()。

import re
from cStringIO import StringIO

def _fix_dump(dump, indentSize=2):
    stream = StringIO(dump)
    out = StringIO()
    pat = re.compile('(\s*)([^:]*)(:*)')
    last = None

    prefix = 0
    for s in stream:    
        indent, key, colon = pat.match(s).groups()
        if indent=="" and key[0]!= '-':
            prefix = 0
        if last:
            if len(last[0])==len(indent) and last[2]==':':
                if all([
                        not last[1].startswith('-'), 
                        s.strip().startswith('-')
                        ]):
                    prefix += indentSize
        out.write(" "*prefix+s)
        last = indent, key, colon
    return out.getvalue()

答案 2 :(得分:1)

如图所示,您的输出不完整,因为print(yaml.dump())给您 name: foo之后的多余的空行。它也更慢,使用更多 内存,而不是直接流到sys.stdout

您可能正在使用PyYAML,除了仅支持过时的YAML 1.1规范外, 对转储的YAML的控制非常有限。

我建议您使用ruamel.yaml(免责声明:我是该程序包的作者),在这里您可以 分别指定映射和序列的标识,并指出多远 补偿序列元素前的缩进中的破折号:

import sys
import ruamel.yaml

foo = {
    'name': 'foo',
    'my_list': [{'foo': 'test', 'bar': 'test2'}, {'foo': 'test3', 'bar': 'test4'}],
    'hello': 'world'
}


yaml = ruamel.yaml.YAML()
yaml.indent(sequence=4, offset=2)
yaml.dump(foo, sys.stdout)

给出:

name: foo
my_list:
  - foo: test
    bar: test2
  - foo: test3
    bar: test4
hello: world

请注意,键的顺序取决于实现 (但可以控制,因为ruamel.yaml可以使以上内容往返 保持不变)。