前言
最近看到一个题目,看似很简单,其实里面有很深的意义,题目是Python 表达式 i += x 与 i = i + x 等价吗?如果你的回答是yes,那么恭喜你正确了50%,为什么说只对了一半呢? 按照我们的一般理解它们俩是等价的,整数操作时两者没什么异同,但是对于列表操作,是不是也一样呢?
先看下面两段代码:
代码1
> l1 = range(3) > l2 = l1 > l2 += [3] > l1 [0, 1, 2, 3] > l2 [0, 1, 2, 3]
代码2
> l1 = range(3) > l2 = l1 > l2 = l2 + [3] > l1 [0, 1, 2] > l2 [0, 1, 2, 3]
代码1与代码2中的l2的值是一样的,但是l1的值却不一样,说明 i += x 与 i = i + x 是不等价的,那什么情况下等价,什么情况下不等价呢?
弄清楚这个问题之前,首选得明白两个概念:可变对象与不可变对象。
在 Python 中任何对象都有的三个通用属性:唯一标识、类型、值。
唯一标识:用于标识对象的在内存中唯一性,它在对象创建之后就不会再改变,函数 id()可以查看对象的唯一标识
类型:决定了该对象支持哪些操作,不同类型的对象支持的操作就不一样,比如列表可以有length属性,而整数没有。同样地对象的类型一旦确定了就不会再变,函数 type()可以返回对象的类型信息。
对象的值与唯一标识不一样,并不是所有的对象的值都是一成不变的,有些对象的值可以通过某些操作发生改变,值可以变化的对象称之为可变对象(mutable),值不能改变的对象称之为不可变对象(immutable)
不可变对象(immutable)
对于不可变对象,值永远是刚开始创建时候的值,对该对象做的任何操作都会导致一个新的对象的创建。
> a = 1 > id(a) 32574568 > a += 1 > id(a) 32574544
整数 “1” 是一个不可变对象,最初赋值的时候,a 指向的是整数对象 1 ,但对变量a执行 += 操作后, a 指向另外一个整数对象 2 ,但对象 1 还是在那里没有发生任何变化,而 变量 a 已经指向了一个新的对象2。常见的不可变对象有:int、tuple、set、str。
可变对象(mutable)
可变对象的值可以通过某些操作动态的改变,比如列表对象,可以通过append方法不断地往列表中添加元素,该列表的值就在不断的处于变化中,一个可变对象赋值给两个变量时,他们共享同一个实例对象,指向相同的内存地址,对其中任何一个变量操作时,同时也会影响另外一个变量。
> x = range(3) > y = x > id(x) 139726103041232 > id(y) 139726103041232 > x.append(3) > x [0, 1, 2, 3] > y [0, 1, 2, 3] > id(x) 139726103041232 > id(y) 139726103041232
执行append操作后,对象的内存地址不会改变,x、y 依然指向的是原来同一个对象,只不过是他的值发生了变化而已。
理解完可变对象与不可变对象后,回到问题本身,+= 与 +的区别在哪里呢?
+= 操作首先会尝试调用对象的 __iadd__方法,如果没有该方法,那么尝试调用__add__方法,先来看看这两个方法有什么区别
__add__和 __iadd__ 的区别
- __add__ 方法接收两个参数,返回它们的和,两个参数的值均不会改变。
- __iadd__ 方法同样接收两个参数,但它是属于 in-place 操作,就是说它会改变第一个参数的值,因为这需要对象是可变的,所以对于不可变对象没有__iadd__方法。
> hasattr(int, '__iadd__') False > hasattr(list, '__iadd__') True
显然,整数对象是没有__iadd__的,而列表对象提供了__iadd__方法。
> l2 += [3] # 代码1:使用__iadd__,l2的值原地修改
代码1中的 += 操作调用的是__iadd__方法,他会原地修改l2指向的那个对象本身的值
> l2 = l2 + [3] # 代码2:调用 __add__,创建了一个新的列表,赋值给了l2
而代码2中的 + 操作调用的是 __add__ 方法,该方法会返回一个新的对象,原来的对象保持不变,l1还是指向原来的对象,而l2已经指向一个新的对象。
以上就是表达式 i += x 与 i = i + x 的区别。因此对于列表进行 += 操作时,会存在潜在的bug,因为l1会因为l2的变化而发生改变,就像函数的参数不宜使用可变对象作为关键字参数一样。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
P70系列延期,华为新旗舰将在下月发布
3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。
而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?
根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。
更新日志
- 雨林唱片《赏》新曲+精选集SACD版[ISO][2.3G]
- 罗大佑与OK男女合唱团.1995-再会吧!素兰【音乐工厂】【WAV+CUE】
- 草蜢.1993-宝贝对不起(国)【宝丽金】【WAV+CUE】
- 杨培安.2009-抒·情(EP)【擎天娱乐】【WAV+CUE】
- 周慧敏《EndlessDream》[WAV+CUE]
- 彭芳《纯色角3》2007[WAV+CUE]
- 江志丰2008-今生为你[豪记][WAV+CUE]
- 罗大佑1994《恋曲2000》音乐工厂[WAV+CUE][1G]
- 群星《一首歌一个故事》赵英俊某些作品重唱企划[FLAC分轨][1G]
- 群星《网易云英文歌曲播放量TOP100》[MP3][1G]
- 方大同.2024-梦想家TheDreamer【赋音乐】【FLAC分轨】
- 李慧珍.2007-爱死了【华谊兄弟】【WAV+CUE】
- 王大文.2019-国际太空站【环球】【FLAC分轨】
- 群星《2022超好听的十倍音质网络歌曲(163)》U盘音乐[WAV分轨][1.1G]
- 童丽《啼笑姻缘》头版限量编号24K金碟[低速原抓WAV+CUE][1.1G]