シリアル化したい辞書のリストがあります。
_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
_
PyYAML documentationdump()
引数について非常に簡単に説明しており、この特定の主題については何も持っていないようです。
ファイルを手動で編集して改行を追加すると、読みやすさが大幅に向上し、構造は後で問題なく読み込まれますが、dumpメソッドで生成する方法がわかりません。
そして一般的に、単純なインデント以外に出力フォーマットをより細かく制御する方法はありますか?
ライブラリを使用してこれを行う簡単な方法はありません(yamlダンパー構文ツリーのノードオブジェクトはパッシブであり、この情報を出力できません)。
stream = yaml.dump(list_of_dicts, default_flow_style = False)
file.write(stream.replace('\n- ', '\n\n- '))
PyYAMLのドキュメントでは、言うことがあまりないため、dump()
引数について簡単に説明しているだけです。この種の制御は、PyYAMLでは提供されません。
ロードされたYAMLにそのような空の(およびコメント)行を保存できるようにするために、私は _ruamel.yaml
_ ライブラリの開発を開始しました。機能が追加され、バグが修正されました。 _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(16進数、8進数、2進数)およびfloatの形式を保存/簡単に設定することもできます。また、マッピングとシーケンスの個別のインデント仕様(ただし、個々のマッピングまたはシーケンスではありません)。
少し不格好ですが、私は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)
あなたはそれをこのように呼びます:
print dump(python_dict, default_flow_style=False, width=79, Dumper=MyDumper)