python tuple不可变但可以更改set type属性

时间:2014-03-22 08:25:41

标签: python attributes set namedtuple

我知道python中的一个namedtuple是不可变的,它的属性值不能直接重新分配

N = namedtuple("N",['ind','set','v'])
def solve()
    items=[]
    R = set(range(0,8))
    for i in range(0,8):
        items.append(N(i,R,8))  
    items[0].set.remove(1)
    items[0].v+=1

最后,我在为属性指定新值时,v' 将不起作用。但删除元素' 1'从items [0]的set 属性起作用。

如果set属性属于List类型

,为什么会这样呢?

2 个答案:

答案 0 :(得分:0)

你改变了集合,而不是元组。集合是可变的。

>>> s = set()
>>> t = (s,)
>>> l = [s]
>>> d = {42: s}
>>> t
(set([]),)
>>> l
[set([])]
>>> d
{42: set([])}
>>> s.add('foo')
>>> t
(set(['foo']),)
>>> l
[set(['foo'])]
>>> d
{42: set(['foo'])}

答案 1 :(得分:0)

不会赋予元组内可变对象赋予不变性。 所有不变性意味着您无法更改存储的特定对象 - 即,您无法重新分配items[0].set。无论该变量的类型如何,此限制都是相同的 - 如果它是列表,则items[0].list = items[0].list + [1,2,3]会失败(无法将其重新分配给新对象),但执行items[0].list.extend([1,2,3])会起作用。< / p>

以这种方式思考:如果您将代码更改为:     new_item = N(i,R,8)

然后new_item.set现在是R的别名(Python在重新分配时不会复制对象)。如果元组赋予可变成员不变性,那么您期望R.remove(1)做什么?由于new_item.set 相同,因此您对其中的任何更改都将在另一个中可见。如果该集合已成为不可变因为它已成为元组的成员,R.remove(1)将突然失败。 Python中的所有方法调用都工作或失败,具体取决于对象,而不是变量 - R.remove(1)new_item.set.remove(1)必须以相同的方式运行。

这也意味着:

R = set(range(0,8))
for i in range(0,8):
    items.append(N(i,R,8)) 

可能有一个微妙的错误。 R永远不会在此处重新分配,因此items中的每个命名元组都会获得相同的设置。您可以通过注意items[0].set is items[1].set为True来确认这一点。所以,任何时候你改变它们中的任何一个 - 或者R - 修改都会出现在各处(它们只是同一个对象的不同名称)。

当您执行

之类的操作时,通常会出现此问题
a = [[]] * 3
a[0].append(2)

现在将成为[[2], [2], [2]]。围绕这个一般性问题有两种方法:

首先,在分配时要非常小心地创建一个 new 可变对象,除非你故意想要一个别名。在嵌套列表示例中,通常的解决方案是执行a = [[] for _ in range(3)]。对于元组中的集合,将行R = ...移动到循环中的,以便将其重新分配给每个namedtuple new 集。< / p>

第二种方法是使用不可变类型。将R设为frozenset,添加和删除元素的功能就会消失。