为PyYAML转储(II)的部分指定样式:序列

时间:2015-03-10 21:24:07

标签: python formatting yaml

这是Specifying styles for portions of a PyYAML dump的后续问题:

考虑将以下代码作为输入手动格式化的YAML数据。我正在修改YAML数据,但希望在写入的YAML文件中保留单行边缘。

import yaml

st2 = yaml.load("""
edges:
- [1, 2]
- [2, 1, [1,0]]
""")
print yaml.dump(st2)

class blockseq( dict ): pass
def blockseq_rep(dumper, data):
    return dumper.represent_mapping( u'tag:yaml.org,2002:seq', data, flow_style=False )

class flowmap( dict ): pass
def flowmap_rep(dumper, data):
    return dumper.represent_mapping( u'tag:yaml.org,2002:map', data, flow_style=True )

class blockseqtrue( dict ): pass
def blockseqtrue_rep(dumper, data):
    return dumper.represent_mapping( u'tag:yaml.org,2002:seq', data, flow_style=True )

yaml.add_representer(blockseq, blockseq_rep)
yaml.add_representer(blockseqtrue, blockseqtrue_rep)
yaml.add_representer(flowmap, flowmap_rep)

st2['edges'] = [ blockseqtrue(x) for x in st2['edges'] ]
print yaml.dump(st2)

此脚本退出并显示以下输出错误:

edges:
- [1, 2]
- - 2
  - 1
  - [1, 0]  

Traceback (most recent call last):
  File "test-yaml-rep.py", line 42, in <module>
    st2['edges'] = [ blockseqtrue(x) for x in st2['edges'] ]
TypeError: cannot convert dictionary update sequence element #0 to a sequence 

2 个答案:

答案 0 :(得分:2)

你的问题是,我所使用的两个类都使用了dicts,而不是列表。你想要一些适用于列表的东西:

class blockseqtrue( list ): pass
def blockseqtrue_rep(dumper, data):
    return dumper.represent_sequence( u'tag:yaml.org,2002:seq', data, flow_style=True )

Python列表是YAML序列/ seqs。 Python dicts是YAML映射/映射。

答案 1 :(得分:2)

如果你在python中进行往返YAML,那么使用ruamel.yaml(我是PyYAML增强版本的作者)要容易得多。 它保留了流/块样式序列/列表和mapppings / dicts(以及注释):

import ruamel.yaml

st2 = ruamel.yaml.load("""
edges:
- [1, 2]    # <- change the second item
- [2, 1, [1,0]]
""", Loader=ruamel.yaml.RoundTripLoader)

st2['edges'][0][1] = 42
print(ruamel.yaml.dump(st2, Dumper=ruamel.yaml.RoundTripDumper))

会给你:

edges:
- [1, 42]   # <- change the second item
- [2, 1, [1, 0]]

正如您所看到的,这将保留最顶层序列上的块样式(edges的值)和其他序列上的流样式。