【问题标题】:factoring mapping key in a yaml file在 yaml 文件中分解映射键
【发布时间】:2019-01-08 17:46:09
【问题描述】:

我有这个 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))

【问题讨论】:

    标签: python yaml flatten pyyaml


    【解决方案1】:

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

    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-loader,也可以处理键序列,但它不会巧妙地转储返回,导致 ? 标记显式键。

    • 用于 Python 的 proposal for a frozendict 未被接受,因此没有等效项,甚至在标准库中也没有用于 dicttuple 用于 listruamel.yaml不支持映射作为开箱即用的键。如果你有这样一个frozendict,当然可以将它添加到ruamel.yaml的构造函数中。

    • 虽然 Python 中有一个 frozensetYAML 中有一个集合,但ruamel.yaml 目前接受以下输入:

      !!set {a , b}: value
      
    • 可能不用说:如果不删除并重新添加键值对,就无法以编程方式更改此类键的元素。

    【讨论】:

      猜你喜欢
      • 2018-11-13
      • 1970-01-01
      • 1970-01-01
      • 2017-04-08
      • 1970-01-01
      • 2020-05-19
      • 1970-01-01
      • 2012-11-12
      • 2016-03-03
      相关资源
      最近更新 更多