A workaround for Python's missing frozen-dict type?
在Python中,当您想使用列表作为某些字典的键时,可以将它们转换为元组,这些元组是不可变的,因此是可哈希的。
1 2 3
| >>> a = {}
>>> a[tuple(list_1)] = some_value
>>> a[tuple(list_2)] = some_other_value |
当您想使用set对象作为某个字典的键时,也会发生同样的情况——您可以构建一个frozenset,它同样是不可变的,因此是可哈希的。
1 2 3
| >>> a = {}
>>> a[frozenset(set_1)] = some_value
>>> a[frozenset(set_2)] = some_other_value |
但似乎字典里没有对等的词。
我想到的第一个想法(最后发现很糟糕)是用str(some_dict)作为一把钥匙。但是,字典总是使用不同的哈希函数,因此相同字典的字符串可能不同。
有没有被称为"良好实践"的变通方法,或者有没有人对如何使用类似字典的对象作为其他字典的键有其他想法?
- 你可以打电话给str(),用collections.OrderedDict吗?
- @SimeonVisser ordered dict:除非您考虑元素添加的顺序是dict值的一部分,否则您可能会对您得到的行为感到惊讶-我曾经设想ordereddict是一个树映射,按键排序,但遗憾的是(对于这个用例)不是。
我为这个问题找到了一个很好的解决方法,那就是构建一个包含字典项的冻结集:
1 2 3 4 5
| >>> a = {'key1' : 'val1', 'key2' : 'val2'}
>>> b = frozenset(a.items())
>>> frozenset_restored_to_dict = dict(b)
>>> frozenset_restored_to_dict
{'key2': 'val2', 'key1': 'val1'} |
从代码中可以看出,b是一个frozenset,它是不可变的,可以散列的,并且可以完全恢复为像a这样的常规字典。
- 注意,这要求dict值和键都是可哈希的。
- 很高兴提到从一个frozenset到一个dict的路。
- 但是,这将失去dict对象的最佳属性,即按键查找可以在恒定时间内完成。
- 最好使用tuple而不是frozenset,否则在python3.6上转换时顺序可能会改变。+
- @扎尔海的顺序是整个问题,也是使用frozenset而不是tuple的确切原因。如果使用一个元组,那么两个相等字典的项对可能会被不同的排序,这将导致不相等的元组。这是通过使用frozenset解决的,在这里顺序没有意义,就像在字典中一样。
- @我明白你的意思了。另一方面,从集合中恢复dict,如果后者未排序,则可能导致不同的插入顺序(尽管"相同"的dict比较方式)。在一般情况下,我同意frozenset是一种方式,但是如果他/她的代码依赖于排序顺序,就需要记住潜在的制动排序顺序。
- @Zaarhai您可能在谈论一些特定的和非标准的东西,因为哈希表(python字典)的定义没有有意义的顺序——它们是按照键的哈希值排序的,这可能会不时地有所不同。如果在python中有一个"记住"插入顺序并使用它的新特性,那么这是哈希表的一个非标准特性。
- 顺便问一下,如果他们为字典增加了这样一个特殊的功能,为什么他们不为集合和冻结集合做同样的事情呢?情况也一样。如果他们这样做了,冷冻水溶液就会起作用。
- 是的,我说的是python dicts,不是像cs uni课程中那样的抽象哈希表数据结构。cpython dicts的行为从3.6开始保留插入顺序,它是lang规范的一部分,从3.7 stackoverflow.com/a/39980744/360390开始。集合仍然无序:stackoverflow.com/a/45589769/360390。从某种意义上说,使用tuple会使它表现得像冻结的collections.OrderedDict,如果代码认为dict的顺序不同,那么这可能是一种方法。OrderedDict(a=1,b=2) != OrderedDict(b=2,a=1),而dict(a=1,b=2) == dict(b=2,a=1)。
您可以尝试按顺序听写或查看以下答案:
- "冷冻口述"是什么?
- 不可变字典,仅用作其他字典的键
- 如何在python中创建不可变字典?
Pypi上甚至还有一个包:https://pypi.python.org/pypi/frozendict
您还可以简单地将dict转换为元组(sorted(your_dict.items())),然后用作哈希。
更新:正如评论中提到的,ordereddict是不可显示的。我的错,它真的不应该是散列的,因为它是可变的。
- OrderedDicts也不可散列。
- 注意,可以使用frozenset而不是排序的元组