我有一个defaultdict(list)
,我想制作不可变的,以便我可以将这种类型的对象添加到一个集合中。我知道如何使它成为不可变的,但它需要我写几行代码。在python中没有更简单的方法吗?
在解析完成后,在冻结它之前解析一段数据时,在python中填充(例如defaultdict(list)
是不是很常见?
对象也可以是元组类型,但不能用作dict键,例如:
>>> a = ([1,2],[2,3])
>>> type(a)
<type 'tuple'>
>>> d = dict()
>>> d[a] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
为什么在python中存在一个列表元组也是我不理解的东西。
答案 0 :(得分:1)
为了使一个可变对象成为不可变的,它的所有可变容器必须被它们的不可变对应物替换。所有值本身都是不可变的字典可以简单地变为不可变的。
调整defaultdict(list)
documentation:
import collections as coll
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = coll.defaultdict(tuple)
for k, v in s:
d[k] = d[k] + (v,)
print(d)
# prints
defaultdict(<class 'tuple'>, {'yellow': (1, 3), 'blue': (2, 4), 'red': (1,)})
我们keys
中的defaultdict(tuple)
是不可变的(strings
),值也是tuple
),而不是defaultdict(list)
。
冻结这本词典:
def dict_freeze(d):
# This is the trivial one-line function
# It assumes the values are of immutable types, i.e. no lists.
# It unpacks dict items, sorts and converts to tuple
# sorting isn't strictly necessary, but dictionaries don't preserve order
# thus we could end up with the following:
# d = {'a': 1, 'b': 2} could get frozen as either of the following
# (('a', 1), ('b', 2)) != (('b', 2), ('a', 1))
return tuple(sorted(d.items()))
frozen_d = dict_freeze(d)
print(frozen_d)
# prints
(('blue', (2, 4)), ('red', (1,)), ('yellow', (1, 3)))
因此,我建议在这种情况下使用defaultdict(tuple)而不是defaultdict(list)来冻结,只需解压缩,排序并转换为元组。
答案 1 :(得分:0)
另一种解决方案是使用 pyrsistent 包 link。 Pyrsistent 是一些持久化集合(被一些人称为功能数据结构)。持久性,即它们是不可变的。
我建议使用冻结 link。
一个最小的工作示例(MWE):
from pyrsistent import freeze
d = {"a":1, "b": 2}
d = freeze(d) # immutable dictionary
print(d)
## pmap({'b': 2, 'a': 1})
# Try to change a key-value
d["b"] = 10
## TypeError: 'PMap' object does not support item assignment
# If you want to change a blue you need to create a new object using "update"
d.update({"b":10})
## pmap({'b': 10, 'a': 1})