首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >处理YAML重复密钥条目的灵活性

处理YAML重复密钥条目的灵活性
EN

Stack Overflow用户
提问于 2019-11-25 12:19:26
回答 1查看 624关注 0票数 0

我使用YAML文件允许用户将串行工作流配置为我正在开发的python程序:

代码语言:javascript
复制
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字典中的列表,请避免重复问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-26 07:45:49

在解析时,ruamel.yaml除了位于文档的根级别之外,没有深度的概念(除其他外,为了允许根级文本标量不缩进)。添加这样一个深度的概念将是困难的,因为您必须处理别名和可能的数据递归事件,我也不确定这通常意味着什么(尽管对于您的例子来说已经足够清楚了)。

在ruamel.yaml的默认往返加载程序中创建映射的方法相当长。但是,如果要将映射值混在一起,就不应该期望能够将它们转储回去。更不用说保留注释、别名等了。下面假设您将使用更简单的安全加载程序,有别名和/或合并键。

代码语言:javascript
复制
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'])

这意味着:

代码语言:javascript
复制
{'method1': [{'param_x': 44}, {'param_x': 22}], 'method2': [{'param_y': 14, 'param_t': 'string'}]}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59031702

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档