我知道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类型
,为什么会这样呢?答案 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
,添加和删除元素的功能就会消失。