python中a += b与a = a + b不等价。

偶然发现的坑,记录一下

示例代码

def func_a():
	a = ['a']
	b = a
	b += ['b']
	print(a,b,id(a)==id(b))

def func_b():
	a = ['a']
	b = a
	b = b + ['b']
	print(a,b,id(a)==id(b))

func_a()     #运行结果为['a', 'b'] ['a', 'b'] True
func_b()     #运行结果为['a'] ['a', 'b'] False

初步分析

我们知道b = b + [‘b’]这样的加法赋值运算,python解释器会先执行b + [‘b’]生成一个新的列表对象,然后将新的列表赋值给变量b。所以最初的分析是+=运算类似于append方法,是对列表对象就地修改。

深入分析

我们知道,加法运算是通过__add__方法实现的,而+=运算则是通过__iadd__方法实现。通过dis库查看字节码可以看出区别:

import dis

def func_a():
	a = ['a']
	b = a
	b += ['b']

def func_b():
	a = ['a']
	b = a
	b = b + ['b']
    
dis.dis(func_a)
dis.dis(func_b)

>>>
  4           0 LOAD_CONST               1 ('a')
              2 BUILD_LIST               1
              4 STORE_FAST               0 (a)

  5           6 LOAD_FAST                0 (a)
              8 STORE_FAST               1 (b)

  6          10 LOAD_FAST                1 (b)
             12 LOAD_CONST               2 ('b')
             14 BUILD_LIST               1
             16 INPLACE_ADD     #<====
             18 STORE_FAST               1 (b)
             20 LOAD_CONST               0 (None)
             22 RETURN_VALUE
  9           0 LOAD_CONST               1 ('a')
              2 BUILD_LIST               1
              4 STORE_FAST               0 (a)

 10           6 LOAD_FAST                0 (a)
              8 STORE_FAST               1 (b)

 11          10 LOAD_FAST                1 (b)
             12 LOAD_CONST               2 ('b')
             14 BUILD_LIST               1
             16 BINARY_ADD     #<====
             18 STORE_FAST               1 (b)
             20 LOAD_CONST               0 (None)
             22 RETURN_VALUE

发现b += [‘b’]和b = b + [‘b’]在标记的位置字节码是不同的,+=是就地添加,而+仅仅是二进制加法。

举一反三

与加法相同的,是通过__mul__实现,=是通过__imul__实现,其原理是一致的。
值得注意的是,不可变类型(int、str、tuple等)执行+=和*=时是会生成新的不同内存ID的对象的。
最后留个小问题,下面函数会报错吗?函数的执行结果是什么?

def func_a():
    a = (1,2,[3,4])
    b = a[2]
    b += [5]
    print(a)

def func_b():
    a = (1,2,[3,4])
    a[2].append(5)
    print(a)
    
def func_c():
    a = (1,2,[3,4])
    try:
        a[2] += [5]
    except TypeError as e:
        print(e)
        print(a)
def func_d():
    a = (1,2,[3,4])
    try:
        a[1] = 5
    except TypeError as e:
        print(e)
        print(a)

    
func_a()
func_b()
func_c()
func_d()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值