python - 流利的Python书,示例2.15

标签 python

我正在读 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/

相关文章:

python - 文件未找到错误: [Errno 2] No such file or directory: '/tmp/cats-v-dog

python - 限制groupby操作

python - 将蒙版图像保存为 FITS

python - 获取根据修改日期排序的文件夹列表

python - Boofuzz 不会在崩溃后重新启动进程

python - 是否有任何 Python 3 模块来创建 PDF 文件?

python - 覆盖内部函数

python - 给定两个 32 位数字 N 和 M,以及两个位位置 i 和 j。写一个方法让 N 中 i 和 j 之间的所有位都等于 M

python - 如何防止VLAN标记从套接字接收的数据包中剥离?

python - AWS Glue 转换