我使用YAML文件允许用户将串行工作流配置为我正在开发的python程序:
step1:
method1:
param_x: 44
method2:
param_y: 14
param_t: string
method1:
param_x: 22
step2:
method2:
param_z: 7
method1:
param_x: 44
step3:
method3:
param_a: string然后在python中进行解析,并将其存储为字典。现在,我知道在YAML和python字典中不允许重复键(为什么,顺便说一句?),但考虑到YAML的清晰性和极简性,YAML对于我的情况来说似乎是完美的。
我试图遵循这个问题(Getting duplicate keys in YAML using Python)中提出的一种方法。但是,在我的例子中,有时它们是重复的,有时不是,并且使用建议的construct_yaml_map,这将创建一个dict或一个列表,这不是我想要的。根据节点深度,我希望能够在上发送键和值--二级 (method1,method2,.)对于python字典中的列表,请避免重复问题。
发布于 2019-11-26 07:45:49
在解析时,ruamel.yaml除了位于文档的根级别之外,没有深度的概念(除其他外,为了允许根级文本标量不缩进)。添加这样一个深度的概念将是困难的,因为您必须处理别名和可能的数据递归事件,我也不确定这通常意味着什么(尽管对于您的例子来说已经足够清楚了)。
在ruamel.yaml的默认往返加载程序中创建映射的方法相当长。但是,如果要将映射值混在一起,就不应该期望能够将它们转储回去。更不用说保留注释、别名等了。下面假设您将使用更简单的安全加载程序,有别名和/或合并键。
import sys
import ruamel.yaml
yaml_str = """\
step1:
method1:
param_x: 44
method2:
param_y: 14
param_t: string
method1:
param_x: 22
step2:
method2:
param_z: 7
method1:
param_x: 44
step3:
method3:
param_a: string
"""
from ruamel.yaml.nodes import *
from ruamel.yaml.compat import Hashable, PY2
class MyConstructor(ruamel.yaml.constructor.SafeConstructor):
def construct_mapping(self, node, deep=False):
if not isinstance(node, MappingNode):
raise ConstructorError(
None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark
)
total_mapping = self.yaml_base_dict_type()
if getattr(node, 'merge', None) is not None:
todo = [(node.merge, False), (node.value, False)]
else:
todo = [(node.value, True)]
for values, check in todo:
mapping = self.yaml_base_dict_type() # type: Dict[Any, Any]
for key_node, value_node in values:
# keys can be list -> deep
key = self.construct_object(key_node, deep=True)
# lists are not hashable, but tuples are
if not isinstance(key, Hashable):
if isinstance(key, list):
key = tuple(key)
if PY2:
try:
hash(key)
except TypeError as exc:
raise ConstructorError(
'while constructing a mapping',
node.start_mark,
'found unacceptable key (%s)' % exc,
key_node.start_mark,
)
else:
if not isinstance(key, Hashable):
raise ConstructorError(
'while constructing a mapping',
node.start_mark,
'found unhashable key',
key_node.start_mark,
)
value = self.construct_object(value_node, deep=deep)
if key in mapping:
if not isinstance(mapping[key], list):
mapping[key] = [mapping[key]]
mapping[key].append(value)
else:
mapping[key] = value
total_mapping.update(mapping)
return total_mapping
yaml = ruamel.yaml.YAML(typ='safe')
yaml.Constructor = MyConstructor
data = yaml.load(yaml_str)
for k1 in data:
# might need to guard this with a try-except for non-dictionary first-level values
for k2 in data[k1]:
if not isinstance(data[k1][k2], list): # make every second level value a list
data[k1][k2] = [data[k1][k2]]
print(data['step1'])这意味着:
{'method1': [{'param_x': 44}, {'param_x': 22}], 'method2': [{'param_y': 14, 'param_t': 'string'}]}https://stackoverflow.com/questions/59031702
复制相似问题