我对修改元组成员感到有些困惑。以下不起作用:
>>> thing = (['a'],)
>>> thing[0] = ['b']
TypeError: 'tuple' object does not support item assignment
>>> thing
(['a'],)
但这确实有效:
>>> thing[0][0] = 'b'
>>> thing
(['b'],)
也有效:
>>> thing[0].append('c')
>>> thing
(['b', 'c'],)
不能正常工作(嗯?!):
>>> thing[0] += 'd'
TypeError: 'tuple' object does not support item assignment
>>> thing
(['b', 'c', 'd'],)
看似与以前相同,但有效:
>>> e = thing[0]
>>> e += 'e'
>>> thing
(['b', 'c', 'd', 'e'],)
那么,当你能够并且不能修改元组内的某些内容时,游戏的规则到底是什么?它似乎更像禁止使用赋值成员的赋值运算符,但最后两个案例让我感到困惑。
答案 0 :(得分:9)
您可以始终修改元组内的可变值。你看到的令人费解的行为
>>> thing[0] += 'd'
由+=
引起。 +=
运算符执行就地添加但 赋值 - 就地添加只能用于文件,但由于元组是不可变的,所以赋值失败。像
>>> thing[0] = thing[0] + 'd'
更好地解释了这一点。我们可以使用标准库中的dis
module来查看从两个表达式生成的字节码。使用+=
,我们得到INPLACE_ADD
字节码:
>>> def f(some_list):
... some_list += ["foo"]
...
>>> dis.dis(f)
2 0 LOAD_FAST 0 (some_list)
3 LOAD_CONST 1 ('foo')
6 BUILD_LIST 1
9 INPLACE_ADD
10 STORE_FAST 0 (some_list)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
使用+
,我们得到BINARY_ADD
:
>>> def g(some_list):
... some_list = some_list + ["foo"]
>>> dis.dis(g)
2 0 LOAD_FAST 0 (some_list)
3 LOAD_CONST 1 ('foo')
6 BUILD_LIST 1
9 BINARY_ADD
10 STORE_FAST 0 (some_list)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
请注意,我们在两个位置都获得STORE_FAST
。这是当您尝试存储回元组时失败的字节码 - 在工作正常之前出现的INPLACE_ADD
。
这解释了为什么“不工作,无效”的情况会使修改后的列表落后:元组已经有了对列表的引用:
>>> id(thing[0])
3074072428L
然后INPLACE_ADD
修改了列表,STORE_FAST
失败了:
>>> thing[0] += 'd'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
所以元组仍然引用了相同的列表,但列表已经就地修改了:
>>> id(thing[0])
3074072428L
>>> thing[0]
['b', 'c', 'd']
答案 1 :(得分:2)
您无法修改元组,但可以修改元组中包含的内容。列表(以及集合,dicts和对象)是引用类型,因此元组中的“strong”只是一个引用 - 实际列表是一个可变对象该引用指向该引用,并且可以在不更改引用本身的情况下进行修改。
( + ,) <--- your tuple (this can't be changed)
|
|
v
['a'] <--- the list object your tuple references (this can be changed)
thing[0][0] = 'b'
之后:
( + ,) <--- notice how the contents of this are still the same
|
|
v
['b'] <--- but the contents of this have changed
thing[0].append('c')
之后:
( + ,) <--- notice how this is still the same
|
|
v
['b','c'] <--- but this has changed again
+=
错误的原因是它不完全等同于.append()
- 它实际上是添加然后是赋值(并且赋值失败),而不是仅仅追加到位。 / p>
答案 2 :(得分:1)
您不能替换元组的元素,但可以替换元素的全部内容。这将有效:
thing[0][:] = ['b']