我还通过使用 Eclipse/PyDev 下的调试器对此进行了研究,并研究了返回的 YAML 对象的结构。我发现通过将 YAML 对象改造成使用 python 元组而不是列表,我可以在不使用特定于 python 的类型的情况下绕过关于不可哈希键的特定错误,但这只是一种解决方案的错觉。PyYAML 中字典的键必须是 MappingNode。尽管这可以实现为一个 Python 值元组,但在内部它仍然被视为一个集合(即受到唯一化和重新排序)。这意味着不同的元组(例如 (a,a,b)、(a,b,a)、(b,a) 等)可能最终被视为同一个键,这不是您想要的。
对于信息,这就是我所做的。当遇到类似这样的 YAML 序列时,我定义了一个 Python 类来使用元组而不是列表构造一个新的 MappingNode:
class Key(yaml.YAMLObject):
yaml_tag = "tag:example.com:2013:Key"
@classmethod
def from_yaml(cls, loader, node):
if isinstance(node, yaml.SequenceNode):
new_values = []
for v in node.value:
new_values.append( (v, yaml.ScalarNode(tag=u'tag:yaml.org,2002:null'), value=u'')) )
node = yaml.MappingNode(tag=node.tag, value=tuple(new_values))
return loader.construct_yaml_object(node,cls)
然后,我在我的 YAML 数据中将此类用于序列键的键,如下所示:
!<tag:example.com:2013:Key> [a, b]: 3
或者:
%TAG !mytags! tag:example.com:2013:
---
......
!mytags!Key [a, b]: 3
但是,正如我所解释的,这并不能以您期望的方式保留序列。就个人而言,我不会在任何实际应用程序中使用此代码/方法。
对我来说,使用集合而不是序列似乎更安全,尽管这并不是你所问的。这使用来自Language-Independent Types for YAML Version 1.1的集合类型。我对上面的序列类型使用了类似的方法,但是由于 PyYAML 使用 Python 列表作为 MappingType 的键,我只需要将其更改为如下所示的元组:
class Key(yaml.YAMLObject):
yaml_tag = "tag:example.com:2013:Key"
@classmethod
def from_yaml(cls, loader, node):
if isinstance(node, yaml.MappingNode):
node.value = tuple(node.value)
return loader.construct_yaml_object(node, cls)
并使用集合作为 YAML 数据中的键,如下所示:
!mytags!Key {a, b}: 3
在我看来,所有这些都像是 PyYAML 的一个限制:理论上,我认为 YAML 本身没有任何东西不允许将序列用作您想要的键。