python中a+=b真的等于a=a+b吗

今天wayne老师讲函数函数默认的作用域的时候,讲到列表+= 和 +的区别,一脸懵逼,自己遇到了知识盲区。
在这里总结一下+= 和 +的区别

一丶直入主题,先看示例

  • 对象是列表的情况
In [1]: a = [1, 2, 3]
In [2]: a += (4,)

In [3]: a
Out[3]: [1, 2, 3, 4]
In [4]: b = [1, 2, 3]

In [5]: b = b + (4,)
Traceback (most recent call last):

  File "<ipython-input-5-f5a90945a99d>", line 1, in <module>
    b = b + (4,)
    
TypeError: can only concatenate list (not "tuple") to list

上面不难看出,a += b和a = a + b并不是完全等价的。
但是list和tuple相加操作,理应报错,为什么使用了+=却没有报错呢?

二丶深入理解

  • 实际上,+= 会首先调用__iadd__方法,如果没有__iadd__,则调用 __add__方法,但是 + 只会调用 __add__这个方法。
  • 对于不可变对象:元组丶字符串、数字、浮点数、bytes等这种对象,他们没有__iadd__对象,所以对他们来说,+= 和 + 是等价的。

对于__iadd__这个方法,当对象是列表时,

def __iadd__(self, values):
    self.extend(values)
    return self

官方文档: 类似__iadd__的这些方法尝试进行自身操作(修改self),并返回结果(结果应该但非必须为self)。如果某个方法未被定义,则被退回到普通方法.例如x是具有_iadd_方法的类的一个实例,则x += y 就相当于x = x.__iadd__(y).否则就如x + y 的求值一样选择x.__add__(y)或者y.__radd__(x)
Why does a_tuple[i] += [‘item’] raise an exception when the addition works?

所以说,当使用 += 连接列表和元组的时候,本质上是列表使用extend将元组的内容添加进去,所以a的身份地址id也不会变。

下面来验证通过+=和+操作前后的id内存地址的情况

  1. 可变对象
    选列表作为操作对象
In [6]: l1 = [1, 2, 3]

In [7]: l2 = [1, 2, 3]

In [8]: id(l1), id(l2)
Out[8]: (162363016, 162714056)
In [9]: l1 += [4]

In [10]: l2 = l2 + [4]

In [11]: id(l1), id(l2)
Out[11]: (162363016, 138938120)

不难发现,列表经过+=操作后,id内存地址并没有发生改变,但是+却改变了。
2. 不可变对象
选字符串作为操作对象

In [1]: s1 = "a"

In [2]: s2 = "b"

In [3]: id(s1),id(s2)
Out[3]: (6327520, 6325840)  

In [4]: s1 += "c"

In [5]: s2 = s2 + "c"

In [6]: id(s1), id(s2)
Out[6]: (168605264, 168612504) 

不可变对象没有__iadd__方法,所以经过 += 和 + 之后,两者的id内存地址都发生了改变
引用廖雪峰python3教程中函数参数中的小节部分:
默认参数一定要用不可变对象,如果是可变对象,程序运行时会出现逻辑错误!

三丶知识点总结

  • 简单的赋值不创建副本

  • 对 += 或者 *=所做的增量赋值来说,如果左边的变量绑定的是不可变对象,会创建新对象:如果是可变对象,会就地修改

  • 函数的参数以别名的形式传递,这意味着,函数可能会修改通过参数传入的可变对象。这一行为无法避免,除非在本地创建副本或者使用不可变对象

  • 如果默认值是可变容器的话,比如说列表、集合、字典,那么应该把None作为默认值,代码应该像下面编写

def spam(a, b = None):
    if b is None:
        b = []

snake

*理解有不恰当的地方请多多指教

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值