python - 在 yaml 文件中分解映射键
问题描述
我有这个 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))
解决方案
在 YAML 中,您可以有一个复杂的流节点,即使是一个简单的键(即没有?
, 标记)。在YAML 1.2和YAML 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
,我决定在 Python 中通过将它们构造为元组来实现序列键的加载ruamel.yaml
(它支持 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 加载器,它也处理键即序列,但它不会巧妙地转储这些键,从而导致?
标记显式键。一个针对 Python 的 a提案
frozendict
没有被接受,因此没有等效的,甚至在标准库中也没有 adict
whattuple
is for alist
,并且ruamel.yaml
不支持作为开箱即用的键的映射。如果你有这样一个frozendict,你当然可以将它添加到ruamel.yaml
的构造函数中。尽管
frozenset
Python 中有 a ,YAML中有一个 set ,但目前不ruamel.yaml
接受以下输入:!!set {a , b}: value
可能不用说:如果不删除并重新添加键值对,就无法以编程方式更改此类键的元素。
推荐阅读
- svg - SVG - 之间的区别
元素和 元素? - javascript - 格式化第三方导入和其他导入之间的空行
- authorization - XACML 中的 Policy Target 和 Rule Target 有什么区别?
- android - 自动完成 Google Place API
- android - Android Worker 类作为嵌套类
- netcdf - 如何在 Geoserver 上构建数据以获取预测数据
- java - Java中“^=”运算符的目的是什么?
- sql - SQL - 添加空白列并根据计算的 datediff 列中的值进行填充
- java - Apache Camel:从 SFTP 下载文件时,streamDownload 如何在内部工作以及如何将其内容路由到队列?
- batch-file - 如何避免批处理文件中的文件夹名称问题?