如何使用python从字典中编写yaml文件?

Sho*_*uit 5 python yaml pyyaml python-2.7 python-3.x

我有一个 csv 文件,其中包含标题包含键和单元格包含值的数据。我想使用 python 从 csv 文件的内容创建一个 yaml 文件。

我创建了一个 K:V 对的字典;但是,我一直在尝试将 K:V 对放入 yaml 文件中。

yaml 的结构必须是:

key1: value1
key2: value2
key3:
  -  key4: value4
     key5: {key6: [value6]
key7: value7
key8: value8
key9: value9
  -
  -
---
Run Code Online (Sandbox Code Playgroud)

如果我手动创建这些,我将拥有 1000 多个 YAML,因此非常耗时且不切实际。

我正在寻找您更有经验的人可能有的任何想法。

我真的希望输出遍历字典以创建一个巨大的 YAML 列表,如下所示:

key1: value1
key2: value2
key3:
  -  key4: value4
     key5: {key6: [value6]
key7: value7
key8: value8
key9: value9
  -
  -
---
key1: value1
key2: value2
key3:
  -  key4: value4
     key5: {key6: [value6]
key7: value7
key8: value8
key9: value9
  -
  -
---
key1: value1
key2: value2
key3:
  -  key4: value4
     key5: {key6: [value6]
key7: value7
key8: value8
key9: value9
  -
  -
---
key1: value1
key2: value2
key3:
  -  key4: value4
     key5: {key6: [value6]
key7: value7
key8: value8
key9: value9
  -
  -
---
Run Code Online (Sandbox Code Playgroud)

示例代码:

import csv
import yaml

def csv_dict_list(variables_file) :

    reader=csv.DictReader(open(variables_file, 'r'))
    dict_list = []
    for line in reader:
        dict_list.append(line)
    return dict_list

yaml_values = csv_dict_list(sys.argv[1])
Run Code Online (Sandbox Code Playgroud)

无论我在此之后尝试什么,我都无法使用 yaml.load() 或 yaml.load_all() 获得所需的输出。

Ant*_*hon 2

首先,您应该使用dump()or dump_all(),因为您想编写 YAML,而不是使用load().

您还应该意识到,CSV 读取器在 Python 2.7 上返回的内容确实与在 Python 3.6 上不同:在第一个上您得到 a listofdict返回csv_dict_list,在第二个 a listof OrderedDict) 上返回。这本身不是问题,但 PyYAML 转储一个带有排序键的字典,以及一个带有标签的有序字典。

您建议的 YAML 也无效,因为该行中的流程样式映射:

 key5: {key6: [value6]
Run Code Online (Sandbox Code Playgroud)

}在文档结束之前不以 a 结尾,您也不能:

key9: value9
  -
  - 
Run Code Online (Sandbox Code Playgroud)

要么使用:

key9: value9
key10:
  -
  -
Run Code Online (Sandbox Code Playgroud)

或者

key9: 
  - value9
  -
Run Code Online (Sandbox Code Playgroud)

或类似的东西(也没有等效的 Python 数据结构同时具有一个值和一个相同键的列表,因此即使在 Python 中实际上也无法创建类似的东西)。

PyYAML 另外缺乏对缩进块样式序列的支持。如果你这样做:

import yaml
print(yaml.dump(dict(x=[dict(a=1, b=2)]), indent=4))
Run Code Online (Sandbox Code Playgroud)

输出仍将左齐平:

x:
- {a: 1, b: 2}
Run Code Online (Sandbox Code Playgroud)

为了防止使用 PyYAML 时遇到的所有这些问题,并规避 Python 版本的差异,我建议您使用 ruamel.yaml (免责声明:我是该包的作者)和以下代码:

import sys
import csv
import ruamel.yaml

Dict = ruamel.yaml.comments.CommentedMap

def csv_dict_list(variables_file) :
    reader=csv.reader(open(variables_file, 'r'))
    key_list = None
    dict_list = []
    for line in reader:
        if key_list is None:
            key_list = line
            continue
        d = Dict()
        for idx, v in enumerate(line):
            k = key_list[idx]
            # special handling of key3/key4/key5/key6
            if k == key_list[2]:
                d[k] = []
            elif k == key_list[3]:
                d[key_list[2]].append(Dict([(k, v)]))
            elif k == key_list[4]:
                d[key_list[2]][0][k] = dt = Dict()
                dt.fa.set_flow_style()
            elif k == key_list[5]:
                d[key_list[2]][0][key_list[4]][k] = [v]
            else:
                d[k] = v
        dict_list.append(d)
    return dict_list

data = csv_dict_list('test.csv')


yaml = ruamel.yaml.YAML()
yaml.indent(sequence=4, offset=2)
yaml.dump_all(data, sys.stdout)
Run Code Online (Sandbox Code Playgroud)

test.csv

key1,key2,key3,key4,key5,key6,key7,key8,key9
value_a1,value_a2,value_a3,value_a4,value_a5,value_a6,value_a7,value_a8,value_a9
value_b1,value_b2,value_b3,value_b4,value_b5,value_b6,value_b7,value_b8,value_b9
Run Code Online (Sandbox Code Playgroud)

这给出:

key1: value_a1
key2: value_a2
key3:
  - key4: value_a4
    key5: {key6: [value_a6]}
key7: value_a7
key8: value_a8
key9: value_a9
---
key1: value_b1
key2: value_b2
key3:
  - key4: value_b4
    key5: {key6: [value_b6]}
key7: value_b7
key8: value_b8
key9: value_b9
Run Code Online (Sandbox Code Playgroud)

在 Python 2.7 和 Python 3.6 上