python - 如何防止在 YAML 中重新定义 key ?

标签 python yaml pyyaml

每当给定键在同一个字典中出现多次时,是否有任何方法可以使 yaml.load 引发异常?

例如,解析以下 YAML 会引发异常,因为 some_key 出现了两次:

{
  some_key: 0,
  another_key: 1,
  some_key: 1
}

实际上,上述行为对应于关于键重定义的最简单策略。例如,更详细的策略可以指定只有更改分配给键的值的重新定义才会导致异常,或者可以允许将键重新定义的严重级别设置为“警告”而不是“错误” .等等。这个问题的理想答案是能够支持此类变体。

最佳答案

如果您希望加载器抛出错误,那么您应该只定义自己的加载器,并使用一个构造函数来检查键是否已经在映射中 ¹:

import collections
import ruamel.yaml as yaml

from ruamel.yaml.reader import Reader
from ruamel.yaml.scanner import Scanner
from ruamel.yaml.parser_ import Parser
from ruamel.yaml.composer import Composer
from ruamel.yaml.constructor import Constructor
from ruamel.yaml.resolver import Resolver
from ruamel.yaml.nodes import MappingNode
from ruamel.yaml.compat import PY2, PY3


class MyConstructor(Constructor):
    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)
        mapping = {}
        for key_node, value_node in node.value:
            # keys can be list -> deep
            key = self.construct_object(key_node, deep=True)
            # lists are not hashable, but tuples are
            if not isinstance(key, collections.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, collections.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)
            # next two lines differ from original
            if key in mapping:
                raise KeyError
            mapping[key] = value
        return mapping


class MyLoader(Reader, Scanner, Parser, Composer, MyConstructor, Resolver):
    def __init__(self, stream):
        Reader.__init__(self, stream)
        Scanner.__init__(self)
        Parser.__init__(self)
        Composer.__init__(self)
        MyConstructor.__init__(self)
        Resolver.__init__(self)



yaml_str = """\
some_key: 0,
another_key: 1,
some_key: 1
"""

data = yaml.load(yaml_str, Loader=MyLoader)
print(data)

然后抛出一个KeyError

请注意,您在示例中使用的花括号是不必要的。

我不确定这是否适用于 merge keys .


¹ 这是使用 ruamel.yaml 完成的我是其中的作者。 ruamel.yaml是PyYAML的增强版,后者的loader代码应该类似。

关于python - 如何防止在 YAML 中重新定义 key ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34358974/

相关文章:

Python从文件动态导入方法

python - 在 Pandas 中重新编制索引时删除不必要的行

docker - 将 docker 部署到远程主机时传递环境变量

python - PyYAML 可以解析 iso8601 日期吗?

python - 使用 Python 从 YAML 检索批量数据

python - Django ORM 和 Unicode 数据

python - 将 pandas 数据框中的日期时间列转换为秒

yaml - 如何将多个 CSS 文件添加到 R Markdown 中的 Revealjs 演示文稿中?

java - YAML 文件 : Reading Yaml file and Writing the file in Same Format

python - 鲁亚姆 : Possible to define line width?