【Python】序列使用+和*以及增量赋值

序列+和*操作

示例:

l = [1,2,3]
print(id(l), l)

l *= 2      #运用增量乘法后,列表的 ID 没变,新元素追加到列表上
print(id(l), l)

l = l * 2   #此时创建一个新的对象后 赋值给了l
print(id(l), l)

#元组的是不可变序列
t = (1,2,3)
print(id(t), t)
t *= 2      #运用增量乘法后,新的元组被创建
print(id(t), t)

打印如下:

#序列操作
39414280 [1, 2, 3]
39414280 [1, 2, 3, 1, 2, 3]
39394056 [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

#元组操作
39235872 (1, 2, 3)
39303976 (1, 2, 3, 1, 2, 3)

关于+=

此部分内容引自:流畅的Python,2.6节

t = (1, 2, [3,4])
print(id(t), t)

try:
    #此操作会抛出异常,因为元组是不可变序列
    t[2] += [5,6] #TypeError: 'tuple' object does not support item assignment
except TypeError as e:
    print(e)

#实际上打印显示,元组已经被修改
print(id(t), t)

#使用list的extend则不会报错
t[2].extend([7,8])
print(id(t), t)

打印如下:

39416384 (1, 2, [3, 4])
'tuple' object does not support item assignment
39416384 (1, 2, [3, 4, 5, 6])       #元组确实被修改了
39416384 (1, 2, [3, 4, 5, 6, 7, 8])

我们可以使用dis模块查看’t[2] += [5,6]’操作背后的字节码:

>>> dis.dis('t[2] += [5,6]')
  1           0 LOAD_NAME                0 (t)
              2 LOAD_CONST               0 (2)
              4 DUP_TOP_TWO
              6 BINARY_SUBSCR
              8 LOAD_CONST               1 (5)
             10 LOAD_CONST               2 (6)
             12 BUILD_LIST               2
             14 INPLACE_ADD
             16 ROT_THREE
             18 STORE_SUBSCR
             20 LOAD_CONST               3 (None)
             22 RETURN_VALUE

先将t[2]的值存入栈顶TOS,BUILD_LIST来构建一个带有变量5和6的列表,而INPLACE_ADD则表示,计算TOS += [5,6],这一步之所以可以成功,是因为TOS指向的是一个可变对象(列表)。然而最后t[2] = TOS赋值失败了,是因为t是不可变的元组!!!

除非这是我们想要的操作,否则尽量不要使用。流畅的Python的作者总结了3点教训,给大家分享下:

  1. 不要把可变对象放在元组里面。
  2. 增量赋值不是一个原子操作。我们刚才也看到了,它虽然抛出了异常,但还是完成了操作。
  3. 查看 Python 的字节码并不难,而且它对我们了解代码背后的运行机制很有帮助。

猜你喜欢

转载自blog.csdn.net/gx864102252/article/details/80559646
今日推荐