基本上我“理解”使用其他容器作为键的歧义。 - 您是比较参考还是比较其中的值(以及深度)。
那么你不能只专门化一个列表并制作一个自定义比较/哈希运算符吗?正如我在我的应用程序中所知,我希望通过字符串的值(以及当然的相对顺序)来比较字符串列表。
那么我该如何为这类列表编写自定义哈希呢?或者换句话说 - 如何在不导致引入分隔符的情况下对字符串进行字符串化(分隔符可能是字符串的一部分)?!
关于这个问题:https://wiki.python.org/moin/DictionaryKeys
直接说不能使用列表;
也就是说,为什么列表不能用作字典键的简单答案是列表不提供有效的哈希方法。当然,显而易见的问题是,“为什么不呢?”
所以我写这个问题是否有办法使列表可以清除;以及如何制作出令人满意的 Hash 方法。
作为我想要的原因示例,请参阅以下代码:
namelist = sorted(["Jan", "Frank", "Kim"])
commonTrait = newTraits()
traitdict = {}
traitdict[namelist] = commonTrait;
//later I wish to retrieve it:
trait = traitdict[sorted(["Jan", "Frank", "Kim"])]
在这个直接使用中我记得“列表的排序”并不重要(排序只是在上面的代码中完成,以使列表总是相等,如果它们保持相同的内容)。
答案 0 :(得分:11)
如果您需要使用字符串集合作为字典键,您有两个明显的选择:如果订单很重要,请使用tuple
:
>>> d[tuple(['foo', 'bar'])] = 'baz'
>>> d['foo', 'bar']
baz
>>> d['bar', 'foo']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: ('bar', 'foo')
如果订单不能重要,请使用frozenset
:
>>> d[frozenset(['foo', 'bar'])] = 'baz'
>>> d[frozenset(['bar', 'foo'])]
'baz'
>>> d[frozenset(['bar', 'foo', 'bar'])]
'baz'
如果计数很重要但排序不重要,请将sorted
与tuple
一起使用:
>>> d[tuple(sorted(['foo', 'bar']))] = 'baz'
>>> d[tuple(sorted(['bar', 'foo']))]
'baz'
>>> d[tuple(sorted(['bar', 'foo', 'bar']))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: ('bar', 'bar', 'foo')
与Perl哈希或JavaScript对象属性不同,您不需要在Python中对字典键进行字符串化。
现在,关于可变的list
不可清除:Python字典实现使用哈希表结构。它特别要求并假设关键:
__hash__
方法__hash__
方法为同一对象返回不变的数字 a == b
表示a.__hash__() == b.__hash__()
列表不能用作字典键,如:
>>> [].__hash__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
list
课程无法提供同时满足所有要求的__hash__
方法a == b
需要暗示a.__hash__() == b.__hash__()
。
(它*可以提供一个为每个列表返回0的实现,然后它会正常工作,但它会完全反驳哈希的使用,因为所有列表都将映射到字典中的相同插槽,如哈希码会破坏规则2)。
也无法为列表创建__hash__
方法:
>>> [].__hash__ = lambda x: 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object attribute '__hash__' is read-only
当然,如果list
拥有__hash__
方法,我们总能看到会发生什么 - 我们创建了列表的子类并在那里提供__hash__
;哈希码的明显实现是tuple()
:
>>> class hashablelist(list):
... def __hash__(self):
... return hash(tuple(self))
...
>>> x = hashablelist(['a', 'b', 'c'])
>>> y = hashablelist(['a', 'b', 'd'])
>>> d = {}
>>> d[x] = 'foo'
>>> d[y] = 'bar'
>>> d.items()
[(['a', 'b', 'c'], 'foo'), (['a', 'b', 'd'], 'bar')]
>>> y[2] = 'c'
>>> d.items()
[(['a', 'b', 'c'], 'foo'), (['a', 'b', 'c'], 'bar')]
>>> del d[x]
>>> del d[y]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: ['a', 'b', 'c']
>>> d.items()
[(['a', 'b', 'c'], 'bar')]
>>> x in d
False
>>> y in d
False
>>> x in d.keys()
True
>>> y in d.keys()
True
代码显示我们刚刚设法获取了一个损坏的字典 - 即使在['a', 'b', 'c'] -> 'bar'
中可见,也无法通过密钥直接访问或删除.keys()
对。 ,.values()
和.items()
。