在写python代码时,经常用到 Python 对象比较和复制的语句,但语句背后发生了什么,总是不清楚。
举一些用到的例子:
判断a和b是否相等的例子:
if a == b:
...
两个列表之间的拷贝,l2 就是 l1 的拷贝。
l1 = [1, 2, 3]
l2 = list(l1)
其中a == b是比较两个对象的值相等,还是两个对象完全相等呢?
l2 是 l1 的浅拷贝(shallow copy)还是深度拷贝(deep copy)呢?
一、比较’==’ VS ‘is’
等于(==)== 和 is 是 Python 中对象比较常用的两种方式。
简单来说,’=='操作符比较对象之间的值是否相等,比如下面的例子,表示比较变量 a 和 b 所指向的值是否相等。
a==b
而’is’操作符比较的是对象的身份标识是否相等,即它们是否是同一个对象,是否指向同一个内存地址。
在 Python 中,每个对象的身份标识,都能通过函数 id(object) 获得。因此,'is’操作符,相当于比较对象之间的 ID 是否相等,我们来看下面的例子:
a = 10
b = 10
a == b
True
id(a)
4427562448
id(b)
4427562448
a is b
True
首先 Python 会为 10 这个值开辟一块内存,然后变量 a 和 b 同时指向这块内存区域,即 a 和 b 都是指向 10 这个变量,因此 a 和 b 的值相等,id 也相等,a == b和a is b都返回 True。
注意:课程中讲到 -5 到 256 范围内的数字,超过范围会a is b返回了 false,但实验结果并不都是这样的。
课中:对于整型数字来说,以上a is b为 True 的结论,只适用于 -5 到 256 范围内的数字。比如下面这个例子:
a = 257
b = 257
a == b
True
id(a)
4473417552
id(b)
4473417584
a is b
False
把 257 同时赋值给了 a 和 b,可以看到a == b仍然返回 True,因为 a 和 b 指向的值相等。但奇怪的是,a is b返回了 false,并且我们发现,a 和 b 的 ID 不一样了.
事实上,出于对性能优化的考虑,Python 内部会对 -5 到 256 的整型维持一个数组,起到一个缓存的作用。这样,每次你试图创建一个 -5 到 256 范围内的整型数字时,Python 都会从这个数组中返回相对应的引用,而不是重新开辟一块新的内存空间。
但是,如果整型数字超过了这个范围,比如上述例子中的 257,Python 则会为两个 257 开辟两块内存区域,因此 a 和 b 的 ID 不一样,a is b就会返回 False 了。
实验:(pycharm中)
a = 257
b = 257
print(id(a))
print(id(b))
print(a == b)
print(a is b)
1871680969872
1871680969872
True
True
但在命令行中输入确实是False,标识也不相同:
在实际工作中,当我们比较变量时,使用’==‘的次数会比’is’多得多,因为我们一般更关心两个变量的值,而不是它们内部的存储地址。但是,当我们比较一个变量与一个单例(singleton)时,通常会使用’is’。一个典型的例子,就是检查一个变量是否为 None:
if a is None:
...
if a is not None