如何防止在YAML中重新定义键?

kjo*_*kjo 6 python yaml pyyaml

yaml.load当给定的键在同一个字典中出现多次时,有没有办法引发异常?

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

{
  some_key: 0,
  another_key: 1,
  some_key: 1
}
Run Code Online (Sandbox Code Playgroud)

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

Ant*_*hon 2

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

\n\n
import collections\nimport ruamel.yaml as yaml\n\nfrom ruamel.yaml.reader import Reader\nfrom ruamel.yaml.scanner import Scanner\nfrom ruamel.yaml.parser_ import Parser\nfrom ruamel.yaml.composer import Composer\nfrom ruamel.yaml.constructor import Constructor\nfrom ruamel.yaml.resolver import Resolver\nfrom ruamel.yaml.nodes import MappingNode\nfrom ruamel.yaml.compat import PY2, PY3\n\n\nclass MyConstructor(Constructor):\n    def construct_mapping(self, node, deep=False):\n        if not isinstance(node, MappingNode):\n            raise ConstructorError(\n                None, None,\n                "expected a mapping node, but found %s" % node.id,\n                node.start_mark)\n        mapping = {}\n        for key_node, value_node in node.value:\n            # keys can be list -> deep\n            key = self.construct_object(key_node, deep=True)\n            # lists are not hashable, but tuples are\n            if not isinstance(key, collections.Hashable):\n                if isinstance(key, list):\n                    key = tuple(key)\n            if PY2:\n                try:\n                    hash(key)\n                except TypeError as exc:\n                    raise ConstructorError(\n                        "while constructing a mapping", node.start_mark,\n                        "found unacceptable key (%s)" %\n                        exc, key_node.start_mark)\n            else:\n                if not isinstance(key, collections.Hashable):\n                    raise ConstructorError(\n                        "while constructing a mapping", node.start_mark,\n                        "found unhashable key", key_node.start_mark)\n\n            value = self.construct_object(value_node, deep=deep)\n            # next two lines differ from original\n            if key in mapping:\n                raise KeyError\n            mapping[key] = value\n        return mapping\n\n\nclass MyLoader(Reader, Scanner, Parser, Composer, MyConstructor, Resolver):\n    def __init__(self, stream):\n        Reader.__init__(self, stream)\n        Scanner.__init__(self)\n        Parser.__init__(self)\n        Composer.__init__(self)\n        MyConstructor.__init__(self)\n        Resolver.__init__(self)\n\n\n\nyaml_str = """\\\nsome_key: 0,\nanother_key: 1,\nsome_key: 1\n"""\n\ndata = yaml.load(yaml_str, Loader=MyLoader)\nprint(data)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这会抛出一个KeyError.

\n\n

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

\n\n

我不确定这是否适用于合并键

\n\n
\n\n

\xc2\xb9这是使用我是作者的ruamel.yaml完成的。ruamel.yamlPyYAML 的增强版本,后者的加载器代码应该类似。

\n