python修改元组中列表元素的问题
展示问题
在python 2.7版本中,修改一个元组中的列表,得到了错误提示,而值却更改成功。
具体操作
程序1:
1 >>> a = ([],[])
2 >>> id(a)
3 140551915278776
4 >>> a[0].append(1)
5 >>> a
6 ([1], [])
7 >>> id(a)
8 140551915278776
9 >>> a[0] += [2]
10 Traceback (most recent call last):
11 File "<stdin>", line 1, in <module>
12 TypeError: 'tuple' object does not support item assignment
13 >>> a
14 ([1, 2], [])
15 >>> id(a)
16 140551915278776
我们知道tuple是不可变的,当这样操作:
程序2:
1 >>> a = (1, 2)
2 >>> a
3 (1, 2)
4 >>> a[0] = 10
5 Traceback (most recent call last):
6 File "<stdin>", line 1, in <module>
7 TypeError: 'tuple' object does not support item assignment
8 >>> a
9 (1, 2)
会得到一个TypeError的错误,而值是不会改变的。但是在程序1的操作中,使用list的“append”方法可以得到正确的结果,使用“+=”虽然内存地址没有改变,但是得到了错误提示,更加奇怪的是值却成功的修改了。这是怎么一回事?
原理分析
”+=”属于in-place操作,所以
a[0] += [2]
等效于
a[0].extend([2]) #(1)
a[0] = a[0] #(2)
在执行步骤(1)时,没有出错,值已经被更改;执行步骤(2)时,因为’a’是一个tuple,所以这个时候提示了错误信息。最后到结果就出现了程序一呈现到情况。
本质分析
从原理上已经说的通了,现在看看程序内部都发生了什么事情
1 >>> dis.dis(compile('a[0] += [2]', '<string>', 'exec'))
2 1 0 LOAD_NAME 0 (a)
3 3 LOAD_CONST 0 (0)
4 6 DUP_TOPX 2
5 ## 在堆中生成a[0]
6 9 BINARY_SUBSCR
7 10 LOAD_CONST 1 (2)
8 13 BUILD_LIST 1
9 ## 运行+=
10 16 INPLACE_ADD
11 17 ROT_THREE
12 ## a[0]赋值一个新值(出错)
13 18 STORE_SUBSCR
14 19 LOAD_CONST 2 (None)
15 22 RETURN_VALUE
16 >>>
从dis的分析中可以看到,在堆栈中生成一个列表并成功地扩展。在执行STORE_SUBSCR会调用C函数的PyObject_SetItem,检测对象是否支持这个元素。这种情况下的对象是一个元组,So…