2013-01-09 76 views
13

我有字典,我想序列的列表:格式化PyYAML轉儲()輸出

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 documentation有關dump()的討論非常簡短,似乎並不hav在這個特定主題上的任何東西。

手動編輯文件以添加換行提高了可讀性,並且結構仍然正常加載後,但我不知道如何使轉儲方法生成它。

而且一般來說,除了簡單的縮進之外,還有更多的控制輸出格式的方法嗎?

回答

11

有沒有簡單的方法與庫做到這一點(在YAML自卸車語法樹節點對象是被動的,不能發出這個信息),所以我結束了

stream = yaml.dump(list_of_dicts, default_flow_style = False) 
file.write(stream.replace('\n- ', '\n\n- ')) 
+1

謝謝!必須使用類似的列表格式。 PyYAML不會在'-'之前放入縮進,而我們使用的YAML使用庫期望在那裏有一些縮進。所以我們必須做'replace'(' - ',' - ')' – Andrei

+0

這個節點是被動的是真的但是不相關的,因爲節點不會發出任何其他信息(即'ScalarNode's不會發出它們自己的值)。'Emitter'確實得到了一個節點的值(如果適當的話)併發出它,如果你在節點上附加了額外的信息,並且增強了相關的Emitter方法來處理這些額外的信息(就像我在'ruamel.yaml'中做的那樣),那麼絕對沒有必要進行那種粗糙的基於字符串的後期處理。 – Anthon

+0

@Andrei使用['ruamel.yaml'](https://pypi.python.org/pypi/ruamel.yaml)你可以設置'yaml.indent(sequence = 3,offset = 1)',並獲得該輸出沒有後期處理。 – Anthon

0

雖然它的一點點klunky ,我和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

PyYAML文檔只談論dump()參數簡單,因爲沒有太多可說的。這種控制不是由PyYAML提供的。

爲了允許在加載的YAML中保留這樣的空行(和註釋行),我開始開發ruamel.yaml庫,它是停滯PyYAML的超集,它兼容YAML 1.2,添加了許多功能並修復了錯誤。用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(十六進制,八進制,二進制)和浮點格式上保存/簡單設置引號和文字樣式。以及映射和序列的單獨縮進規範(儘管不適用於單個映射或序列)。