为什么下面会抛出异常,虽然它成功了?
>>> t = ([1, 2, 3], 4)
>>> t[0] += [1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
([1, 2, 3, 1], 4)
>>>
答案 0 :(得分:17)
在IRC上找到答案。
t[0] += [1]
是几个不连续的行为:
t[0]
1
的新列表[1]
添加到任何t[0]
t[0]
似乎x += y
基本上是x = x + y
(但是,是吗?)
棘手的是+=
意味着分配给元组t
和列表t[0]
t[0] += [1]
不是字面意思 t[0] = t[0] + [1]
,它是:t[0] = t[0].__iadd__([1])
真正发生的是:
__iadd__
都会改变列表并返回它。所以列表(t
中的第一个元素)已经附加了1
。为什么这在明显的视线中不可见?因为像我这样的n00b会期望t[0] += [1]
一起成功或失败,因为它是python的一条短线。但事实并非如此。
答案 1 :(得分:5)
通过使用dis.dis
查看字节码,也可以帮助理解这种行为。
In[5]: dis('t[0] += [1]')
1 0 LOAD_NAME 0 (t)
3 LOAD_CONST 0 (0)
6 DUP_TOP_TWO
7 BINARY_SUBSCR
8 LOAD_CONST 1 (1)
11 BUILD_LIST 1
14 INPLACE_ADD
15 ROT_THREE
16 STORE_SUBSCR
17 LOAD_CONST 2 (None)
20 RETURN_VALUE
t[0]
的值放在堆栈顶部,BINARY_SUBSCR
,在这种情况下是一个(可变)列表。 += [1]
对其执行INPLACE_ADD
,其中在这种情况下,堆栈的顶部是指元组内的列表。 t[0]
分配给堆栈顶部的是STORE_SUBSCR
,由于t
本身是一个不可变的元组,因此在 > +=
分配已经发生。 答案 2 :(得分:2)
Python开发人员在此处写了一个官方解释:https://docs.python.org/2/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works
简短版本是+ =实际上做了两件事,一件接着另一件事:
在这种情况下,步骤1起作用是因为你被允许向列表中添加内容(它们是可变的),但是第2步失败了,因为在创建它们之后你不能把东西放入元组中(元组是不可变的)。
在一个真实的程序中,我建议你不要这样做,因为t [0] .extend(['c'])完全相同。