web-dev-qa-db-ja.com

PyYAML dump()出力のフォーマット

シリアル化したい辞書のリストがあります。

_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メソッドで生成する方法がわかりません。

そして一般的に、単純なインデント以外に出力フォーマットをより細かく制御する方法はありますか?

20
nope

ライブラリを使用してこれを行う簡単な方法はありません(yamlダンパー構文ツリーのノードオブジェクトはパッシブであり、この情報を出力できません)。

stream = yaml.dump(list_of_dicts, default_flow_style = False)
file.write(stream.replace('\n- ', '\n\n- '))
16
Yuri Baburov

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の形式を保存/簡単に設定することもできます。また、マッピングとシーケンスの個別のインデント仕様(ただし、個々のマッピングまたはシーケンスではありません)。

3
Anthon

少し不格好ですが、私は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)
1