使对象不可变

时间:2015-05-12 11:52:48

标签: python

我有一个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中存在一个列表元组也是我不理解的东西。

2 个答案:

答案 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})