我在计算机上使用 YAML,在模拟器上使用人工可编辑和可读的输入格式。为了人类可读性,输入的某些部分大多适合块样式,而流样式更适合其他部分。
PyYAML 的默认设置是在有嵌套映射或序列的地方使用块样式,在其他地方使用流样式。 *default_flow_style* 允许选择全流式或全块式。
但我想输出更多形式的文件
bonds:
- { strength: 2.0 }
- ...
tiles:
- { color: red, edges: [1, 0, 0, 1], stoic: 0.1}
- ...
args:
block: 2
Gse: 9.4
可以看出,这并没有遵循一致的样式模式,而是根据文件的部分而变化。本质上,我希望能够指定某些块样式序列中的所有值都采用流样式。有没有什么方法可以对倾销进行精细控制?能够以特定顺序转储顶级映射而不需要该顺序(例如,omap)对于可读性也很好。
事实证明,这可以通过为我不想遵循default_flow_style的每个项目定义带有代表的子类来完成,然后在转储之前将所有必要的内容转换为那些。在这种情况下,这意味着我得到类似的东西:
class blockseq( dict ): pass
def blockseq_rep(dumper, data):
return dumper.represent_mapping( u'tag:yaml.org,2002:map', 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 )
yaml.add_representer(blockseq, blockseq_rep)
yaml.add_representer(flowmap, flowmap_rep)
def dump( st ):
st['tiles'] = [ flowmap(x) for x in st['tiles'] ]
st['bonds'] = [ flowmap(x) for x in st['bonds'] ]
if 'xgrowargs' in st.keys(): st['xgrowargs'] = blockseq(st['xgrowargs'])
return yaml.dump(st)
令人烦恼的是,更容易使用的 dumper.represent_list 和 dumper.represent_dict 不允许指定 flow_style,所以我必须指定标签,但系统确实可以工作。
这是 @cge 答案的完整示例(不幸的是,需要付出一些努力才能运行他的示例),并稍加修改:
import yaml
class noflow_dict(dict):
pass
def noflow_dict_rep(dumper, data):
return dumper.represent_mapping("tag:yaml.org,2002:map", data, flow_style=False)
class flow_dict(dict):
pass
def flow_dict_rep(dumper, data):
return dumper.represent_mapping("tag:yaml.org,2002:map", data, flow_style=True)
yaml.add_representer(noflow_dict, noflow_dict_rep)
yaml.add_representer(flow_dict, flow_dict_rep)
def dump(st):
st["flow"] = [flow_dict(x) for x in st["flow"]]
st["noflow"] = [noflow_dict(x) for x in st["noflow"]]
return yaml.dump(st)
obj = {
"flow": [
{"a": 1, "b": 2, "c": 3},
{"d": 4, "e": 5},
],
"noflow": [
{"A": 1, "B": 2, "C": 3},
{"D": 4, "E": 5},
],
}
print(dump(obj))
输出是
flow:
- {a: 1, b: 2, c: 3}
- {d: 4, e: 5}
noflow:
- A: 1
B: 2
C: 3
- D: 4
E: 5
所有积分均归于@cge 的回答。