2013-01-09 14 views
13

Tôi có một danh sách các từ điển, mà tôi muốn serialize:Formatting PyYAML bãi() đầu ra

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) 

sản xuất như sau:

- key_1: value_a 
    key_2: value_b 
- key_1: value_c 
    key_2: value_d 
(...) 
- key_1: value_x 
    key_2: value_y 

Nhưng tôi muốn có được điều nà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 nói về một thời gian ngắn và dường như không có e bất cứ điều gì về chủ đề cụ thể này.

Chỉnh sửa tệp theo cách thủ công để thêm dòng mới cải thiện khả năng đọc khá nhiều và cấu trúc vẫn tải tốt sau đó, nhưng tôi không biết làm cách nào để tạo phương thức kết xuất.

Và nói chung, có cách nào để có nhiều quyền kiểm soát hơn đối với định dạng đầu ra bên cạnh thụt đầu dòng đơn giản không?

Trả lời

11

Không có cách nào dễ dàng để làm điều này với thư viện (đối tượng Node trong yaml cây cú pháp dumper là thụ động và không thể phát ra thông tin này), vì vậy tôi đã kết thúc với

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

Cảm ơn! Đã phải sử dụng một cái gì đó tương tự cho định dạng danh sách. PyYAML không đặt indent trước '-', trong khi YAML tiêu thụ thư viện mà chúng tôi sử dụng dự kiến ​​một số thụt đầu dòng ở đó. Vì vậy, chúng ta phải làm 'thay thế ('-', '-')' – Andrei

+0

Nút đó là thụ động là đúng nhưng không liên quan, vì các nút không phát ra bất kỳ thông tin nào khác (tức là 'ScalarNode' không phát ra giá trị riêng của chúng.).'Emitter' không nhận giá trị của nút (khi thích hợp) và phát ra nó, và nếu bạn gắn thêm thông tin vào các nút, và tăng cường các phương thức Emitter liên quan để xử lý thông tin bổ sung này (như tôi làm trong 'ruamel.yaml'), thì hoàn toàn không cần phải thực hiện loại xử lý hậu kỳ, thô ráp, dựa trên chuỗi đó. – Anthon

+0

@Andrei Với ['ruamel.yaml'] (https://pypi.python.org/pypi/ruamel.yaml) bạn có thể đặt' yaml.indent (sequence = 3, offset = 1) 'và nhận được kết quả đó mà không cần sau xử lý. – Anthon

0

Trong khi một chút klunky của nó , Tôi đã có cùng một mục tiêu như OP. tôi giải quyết nó bằng cách subclassing 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) 

Bạn gọi nó là như thế này:

print dump(python_dict, default_flow_style=False, width=79, Dumper=MyDumper) 
1

PyYAML tài liệu chỉ nói về dump() lập luận một thời gian ngắn, vì không có nhiều điều để nói. Loại kiểm soát này không được PyYAML cung cấp.

Để cho phép bảo quản các dòng rỗng (và chú thích) trong YAML được tải, tôi bắt đầu phát triển thư viện ruamel.yaml, một bộ siêu của PyYAML bị trì trệ, tương thích với YAML 1.2, nhiều tính năng bổ sung và lỗi cố định. Với ruamel.yaml bạn có thể làm:

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) 

và nhận kết quả chính xác giống như chuỗi đầu vào (bao gồm nhận xét).

Bạn cũng có thể xây dựng các đầu ra mà bạn muốn từ đầu:

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) 

Việc chuyển đổi sử dụng yaml.seq() là cần thiết để tạo ra một đối tượng cho phép tập tin đính kèm của trống-đường thông qua các thuộc tính đặc biệt.

Thư viện cũng cho phép lưu giữ/cài đặt dễ dàng các trích dẫn và kiểu chữ trên chuỗi, định dạng int (hex, bát phân, nhị phân) và phao. Cũng như đặc điểm kỹ thuật thụt lề riêng biệt cho ánh xạ và trình tự (mặc dù không cho ánh xạ hoặc trình tự riêng lẻ).