我会说这是 PyYAML 中的一个错误。违规代码是here:
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:
key = self.construct_object(key_node, deep=deep)
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)
mapping[key] = value
return mapping
很明显,没有检查密钥是否存在。您必须对 Constructor 进行子类化,才能创建一个包含 construct_mapping() 并包含检查的子类:
if key in mapping:
warnings.warn(somewarning)
else:
mapping[key] = value
然后使用Constructor 创建一个Loader。
使用ruamel.yaml 可能更简单(免责声明:我是作者
那个包)。假设您禁用DuplicateKeyError,它会正确加载它,
并明确将 YAML 1.1 设置为输入格式:
import sys
import ruamel.yaml
yaml_file = Path('xx.yaml')
yaml = ruamel.yaml.YAML()
yaml.version = (1, 1)
yaml.indent(mapping=3, sequence=2, offset=0)
yaml.allow_duplicate_keys = True
data = yaml.load(yaml_file)
assert data['xxx']['aaa'] == 9
yaml_out = ruamel.yaml.YAML()
yaml_out.dump(data, sys.stdout)
这给出了:
xxx:
aaa: 9
bbb: 10
ccc: 11
您的八进制数将转换为小数(通常该信息是
保留,但在加载旧版 YAML 1.1 时不会)。 PyYAML 将始终这样做。