0

通过阅读 YAML 文件,我想获得以下 python 字典:

mydict = {('x','x'): 4}

或者:

mydict = {['x','x']: 4}

基本上,我想要一个元组或列表作为字典中的键。这是我尝试过的 YAML:

mydict:
   !!python/tuple [e,e]: 4 # valid, but python-specific
   !!python/list [b,b]: 4 # error: "found unhashable key"
   [c,c]: 4 # error: "found unhashable key"
   !!seq [d,d]: 4 # error: "found unhashable key"

我正在使用 PyYAML,因此 YAML 代码必须是 YAML1.1 语法,或者您可以向我推荐一种将此类数据存储在文本文件中的更好方法。我想过json.load,但 JSON 不接受数组作为映射键。

谢谢 =)

4

2 回答 2

1

我还通过使用 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 本身没有任何东西不允许将序列用作您想要的键。

于 2013-07-29T11:18:25.383 回答
0

在 Python 中无法使用列表作为哈希键。它是可变的。你必须使用一个元组。

于 2012-11-24T03:41:17.837 回答