Yaml文件中的分解映射键

时间:2018-08-01 08:16:34

标签: python yaml flatten pyyaml

我有这个YAML文件:

pb:
  {EF:{16, 19}, EH:{16, 19}}

当我应用flattendict Python函数时,我得到了

{('pb', 'EF', 16): None,
 ('pb', 'EF', 19): None,
 ('pb', 'EH', 16): None,
 ('pb', 'EH', 19): None}

我按如下所示搜索YAML文件的语法,以获得相同的结果(我想将我的YAML节点数据作为因数)

pb:
  {EF, EH}, {16, 19}}

你有个主意吗?

这是我的python flattendict函数

#!/usr/bin/env python
#encoding: UTF-8
import codecs
import sys
import yaml
import pprint

import collections

from collections import Mapping
from itertools import chain
from operator import add

_FLAG_FIRST = object()

def flattenDict(d, join=add, lift=lambda x:x):
    results = []
    def visit(subdict, results, partialKey):
        for k,v in subdict.items():
            newKey = lift(k) if partialKey==_FLAG_FIRST else join(partialKey,lift(k))
            if isinstance(v,Mapping):
                visit(v, results, newKey)
            else:
                results.append((newKey,v))
    visit(d, results, _FLAG_FIRST)
    return results

testdata = yaml.safe_load(open('data.yaml', 'r')) 
from pprint import pprint as pp
result = flattenDict(testdata, lift=lambda x:(x,))
pp(dict(result))

1 个答案:

答案 0 :(得分:0)

在YAML中,即使使用简单的键(例如,没有?,标记),您也可以具有复杂的流节点。 YAML 1.2YAML 1.1都是如此。这意味着:

{a: 1, b: 2}: mapping
[1, 2, a]: sequence

是正确的YAML。

问题在于,映射通常作为Python dict和序列作为Python list加载,二者都是可变的,不能被散列,并且不允许作为Python的键dict(尝试执行python -c "{{'a': 1}: 2}")。

在这两行中都出现了

PyYAML(支持YAML 1.1)错误。

由于Python具有list形式的不可变tuple,因此我决定通过在ruamel.yaml中将它们构造为元组来实现Python中序列键的加载(它支持YAML 1.2和YAML 1.1)。所以下面的工作:

import sys
import ruamel.yaml
from pprint import pprint as pp

yaml_str = """\
[pb, EF, 16]: 
[pb, EF, 19]: 
[pb, EH, 16]: 
[pb, EH, 19]: 
"""


yaml = ruamel.yaml.YAML(typ='rt')
# yaml.indent(mapping=4, sequence=4, offset=2)
# yaml.preserve_quotes = True
data = yaml.load(yaml_str)

pp(data)
print('---------')
yaml.dump(data, sys.stdout)

打印:

{('pb', 'EF', 16): None,
 ('pb', 'EF', 19): None,
 ('pb', 'EH', 16): None,
 ('pb', 'EH', 19): None}
---------
[pb, EF, 16]:
[pb, EF, 19]:
[pb, EH, 16]:
[pb, EH, 19]:

如果您尝试在PyYAML中加载上述YAML,则会引发异常:

found unhashable key
  in "<unicode string>", line 1, column 1:
    [pb, EF, 16]: 

注意:

  • 如果您不想往返,请使用typ="safe",它使用速度更快的C加载程序,该C加载程序还可以处理按顺序排列的键,但是它不那么聪明将其转储回去,从而产生标记为?的显式密钥。

  • 用于Python的proposal for a frozendict未被接受,因此,即使在dict的标准库中也没有等效项,对于{{ 1}}和tuple不支持将映射作为开箱即用的键。如果您有这样的问题,当然可以将其添加到list的构造函数中。

  • 尽管Python中有一个frozenset,而YAML中有一个集合,但是ruamel.yaml当前不接受以下内容作为输入:< / p>

    ruamel.yaml
  • 也许无需多说:您不能以编程方式更改此类键的元素,而无需删除并重新添加键值对。