我对修改元组成员有些困惑。以下无效:
>>> 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'],)
那么当您可以和不能修改元组中的某些内容时,游戏的规则到底是什么?这似乎更像是禁止对元组成员使用赋值运算符,但是最后两种情况使我感到困惑。
您可以总是修改元组中的可变值。您通过
看到的令人困惑的行为>>> thing[0] += 'd'
由+=
引起。 +=
运算符执行就地加法,但also和assignment进行就地加法-仅就文件而言,就地加法有效,但由于元组是不可变的,因此分配失败。想起来就像
>>> thing[0] = thing[0] + 'd'
对此进行更好的解释。我们可以使用标准库中的dis
module查看由两个表达式生成的字节码。使用dis
,我们得到一个+=
字节码:
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
注意,我们在both都获得了>>> 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
因此元组仍然具有对[[same列表的引用,但是该列表已就地修改:
>>> thing[0] += 'd'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
引用类型,因此“事物” in元组只是一个引用-实际列表是该对象指向的可变对象参考,并且可以在不更改参考本身的情况下进行修改。
>>> id(thing[0])
3074072428L
>>> thing[0]
['b', 'c', 'd']
( + ,) <--- 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()