我正在读 Luciano Ramalho 的书《流利的 Python》,他写道,如果我们编写这样的代码:
>>>t=(1,2,[30,40])
>>>t[2]+=[50,60]
,那么我们会得到:
a. t becomes (1, 2, [30, 40, 50, 60]).
b. TypeError is raised with the message 'tuple' object does not support item assignment.
我完全明白这一点。
但他的一位读者随后说,如果我们编写如下代码:
>>>t=(1,2,[30,40])
>>>t[2].extend([50,60])
,此时不会引发 TypeError
消息。我想知道为什么会发生这种情况。
如果可能的话,尝试用图片为我描述代码的执行情况。 欣赏它!
最佳答案
我在技术上可能不是100%正确,但我会尽力尽可能直观地解释。 第一种情况:
>>>t=(1,2,[30,40])
>>>t[2]+=[50,60]
让我们看看发生了什么:
当您访问t[2]
时,它会拾取列表[30,40]
,现在在执行+=
操作时,它以特定方式将 [50,60]
添加到 t[2]
:
t[2] = t[2].__iadd__([50,60])
现在右手边有效,这就是为什么t[2]
指向的列表在操作后发生变化,但赋值部分是问题,元组不支持项目分配
。
第二种情况:
>>>t=(1,2,[30,40])
>>>t[2].extend([50,60])
此处,不涉及任何副本,因此无需将副本分配回 t[2]
您只需扩展 t[2]
的列表> 指的是。
让我们看一些不同的示例:
>>> x = [30,40]
>>> t1 = (1,2,x)
>>> t1
(1, 2, [30, 40])
>>> x += [50,60]
>>> x
[30, 40, 50, 60]
>>> t1
(1, 2, [30, 40, 50, 60])
这里,x
指向列表[30, 40]
。 t1
包含该引用。现在你可以独立修改x
了,因为你只是修改列表,现在x
引用的列表变成了[30,40,50,60 ]
,由于 t1[2]
包含对同一列表的引用,它现在显示 [30,40,50,60]
,所以根本不显示令人惊讶。
另一个例子:
>>> t1 = (1, 2, [30, 40])
>>> x = t1[2]
>>> x += [50,60]
>>> x
[30, 40, 50, 60]
>>> t1
(1, 2, [30, 40, 50, 60])
这里,t1[2]
指的是列表[30,40]
,并且您决定指定另一个名称 (x
)到同一个列表。现在您修改 x
引用的列表,对此没有限制,list
是可变对象,因此您不会收到任何错误,并且 >t[2]
指向同一个列表,您并不是试图在 t[2]
中存储另一个修改后的列表,而只是 t[2] 存储的列表
所指向的,它本身已经改变了。
最后,如果我们看一下字节码反汇编,就会更清楚了:
>>> import dis
>>> def f1():
... t = (1,2,[30,40])
... t[2]+=[50,60]
... return t
>>> def f2():
... t = (1,2,[30,40])
... t[2].extend([50,60])
... return t
>>> dis.dis(f1)
2 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 LOAD_CONST 3 (30)
6 LOAD_CONST 4 (40)
8 BUILD_LIST 2
10 BUILD_TUPLE 3
12 STORE_FAST 0 (t)
3 14 LOAD_FAST 0 (t)
16 LOAD_CONST 2 (2)
18 DUP_TOP_TWO
20 BINARY_SUBSCR
22 LOAD_CONST 5 (50)
24 LOAD_CONST 6 (60)
26 BUILD_LIST 2
28 INPLACE_ADD # t[2].__iadd__([50,60])
30 ROT_THREE
32 STORE_SUBSCR # tries to store; t[2] = t[2].__iadd__([50,60])
4 34 LOAD_FAST 0 (t)
36 RETURN_VALUE
>>> dis.dis(f2)
2 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 LOAD_CONST 3 (30)
6 LOAD_CONST 4 (40)
8 BUILD_LIST 2
10 BUILD_TUPLE 3
12 STORE_FAST 0 (t)
3 14 LOAD_FAST 0 (t)
16 LOAD_CONST 2 (2)
18 BINARY_SUBSCR
20 LOAD_METHOD 0 (extend) # loads the same list in t[2]
22 LOAD_CONST 5 (50)
24 LOAD_CONST 6 (60)
26 BUILD_LIST 2
28 CALL_METHOD 1
30 POP_TOP # no store calls
4 32 LOAD_FAST 0 (t)
34 RETURN_VALUE
关于python - 流利的Python书,示例2.15,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58668903/