通过阅读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不接受数组作为映射键。
谢谢=)
答案 0 :(得分:1)
我还通过在Eclipse / PyDev下使用调试器并研究返回的YAML对象的结构来研究这个问题。我发现通过改变YAML对象以使用python元组而不是列表,我可以解决关于不可用密钥的特定错误而不使用特定于python的类型,但这只是一种解决方案的错觉。 PyYAML中字典的键必须是MappingNode。即使这可以作为值的Python元组实现,但在内部它仍然被视为一个集合(即,需要进行统一和重新排序)。这意味着不同的元组(例如(a,a,b),(a,b,a),(b,a)等)可能最终被视为相同的密钥,这不是您想要的。< / p>
有关信息,这就是我所做的。我定义了一个Python类来在遇到YAML序列时使用元组而不是列表来构造一个新的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
然而,正如我所解释的那样,这并没有像你期望的那样保留顺序。我个人不会在任何实际应用程序中使用此代码/方法。
使用套装而不是序列对我来说似乎更安全,尽管它并不是你所要求的。这使用set type中的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本身有任何不允许将序列用作你想要的键。
答案 1 :(得分:0)
无法在Python中将列表用作哈希键。这是可变的。你必须使用一个元组。