前言
Python 中对象的比较有两种方式 == 和 is。两种方式都能判断操作符两侧的变量值是否相等,那么它们的区别是什么呢?通过下面的介绍我们来一探究竟。
比较操作符通常用于条件语句,如下示例:
if a == b: pass
if a is False: pass
== 与 is 的区别
== 操作符比较对象的值是否相等。小明有一块 劳力士 手表,小李也有一块同款 劳力士 手表,这时我们就认为这两块手表相等。
小明的手表 = 劳力士
小李的手表 = 劳力士
小明的手表 == 小李的手表
is 操作符比较对象的身份标识是否相等,即对象在内存中的地址是否相同,如果两个对象的身份标识相等,就说明它们是同一个对象。小明的爸爸称呼小明叫 儿子,小明的女朋友称呼小明叫 老公,但这两个称呼都代表 小明 这个人,即为同一个对象。
爸爸的儿子 = 小明
女朋友的老公 = 小明
爸爸的儿子 is 女朋友的老公
接下来就用代码来展示一下 == 与 is 的区别:
> a = [1, 2, 3] > b = [1, 2, 3] > a == b True > a is b False > id(a) 24603664 > id(b) 24603144
> a = [1, 2, 3] > b = a > a == b True > a is b True > id(a) 24604144 > id(b) 24604144
在 Python 中 id 函数接收一个对象作为参数,并返回该对象在内存中的地址。
由以上代码可以分析出:== 操作符只比较两个对象的值是否相等,但不比较两个对象是否为同一个对象;而 is 操作符并不是比较两个对象的值是否相等,而是会确认两个对象是否为同一个对象,如果为同一个对象,那么它们的值自然相等。
Python 小整数对象池
以上两段代码已经能够体现出 == 与 is 的区别,不过 Python 中也有一些特殊情况,来看下面例子:
> a = 5 > b = 5 > a == b True > a is b True > id(a) 1730274128 > id(b) 1730274128
> a = 257 > b = 257 > a == b True > a is b False > id(a) 48558688 > id(b) 48558720
以上代码看起来就很怪异了,同样的比较操作,只是换了一个数字结果就不同了。
其实出现以上结果的原因在于 Python 自身。Python 出于性能上的考虑,在解释器启动的时候就已经将 -5 到 256 的整数创建到内存中了。而当我们需要创建值在 -5 到 256 的 int 数字的时候,Python 并不会新开辟一块内存去创建数字,而是直接将已存在的对象返回。
但是如果新创建的数字不在这个范围,Python 就会为每个变量单独开辟自己的内存空间。
Python intern 机制
再来看下面关于字符串比较的例子:
> a = 'hello world' > b = 'hello world' > a == b True > a is b False > id(a) 49465408 > id(b) 49465448
> a = 'hello' > b = 'hello' > a == b True > a is b True > id(a) 49429152 > id(b) 49429152
想必根据之前数字比较的例子,你大概也能猜测到以上代码结果不同的原因了。事实上,以上结果同样是 Python 出于对性能的考虑,不过这次 Python 并没有预先将 hello 字符串创建到内存中,而是使用了一种叫 intern 的机制。
关于 intern 机制在这里我们不去深究,以后有机会专门写一篇博客来介绍。总之你需要知道在某些场景下,Python 会对字符串开启 intern 机制来提高性能,从而导致出现上面示例代码的结果。
== 与 is 各自的适用场景
什么时候用 ==、什么时候用 is 呢?
当我们需要比较一个变量与一个 单例 的时候,应该使用 is,其他情况通常使用 ==。
例如拿一个变量去跟 True 或 False 进行比较的时候就应该使用 is,因为用 is 的比较的速度要比用 == 更快。
用 is 比较对象的时候,只需要判断它们是否处于同一块内存地址即可,而用 == 比较更慢的原因在于当用 == 去比较对象的时候会调用对象的 __eq__() 方法,而 __eq__() 方法通常会被重载,执行其内部逻辑往往会多花一些时间。
以下就是一个重载对象 __eq__() 方法的例子:
class MyList(object): def __init__(self, *args): self._list = [*args] def __eq__(self, other): result = False for i in self._list: for j in other._list: if i == j: break else: break else: result = True return result li_1 = MyList(1, 2, 3) li_2 = MyList(1, 2, 3) print(li_1 == li_2) # True
你可以自行尝试修改 __eq__() 方法内部的逻辑来观察其结果。
总结
更新日志
- 杨钰莹.1995-因为有你【新时代】【WAV+CUE】
- 许慧欣.2006-谜【上华】【WAV+CUE】
- 绝区零珂蕾妲驱动盘怎么搭配 珂蕾妲驱动盘及词条选择攻略
- 绝区零强袭鸣徽有哪些 绝区零强袭鸣徽效果介绍
- 魔兽世界奥格瑞玛怎么去幽暗城 奥格瑞玛去幽暗城方法介绍
- 《间谍过家家日记大作战》成就攻略一览
- 完美的音乐品质-群星《红酒杯发烧酒廊情歌》2CD[WAV]
- 群星.2011《高雄国际Hi-End音响大展纪念发烧金碟》[WAV分轨]
- 康康1999-催泪[阿尔法][WAV+CUE]
- 和守望先锋太像?《星鸣特攻》开发商:我们与众不同
- 速通玩家有福了!夏季游戏速通大会正在火热进行中
- 《使命召唤》新处决动作曝光 或联动《死侍3》?
- 《陈百强出道35周年 文质翩翩》4CD[WAV+CUE][1.8GB]
- 邓丽君《思君集》3CD[WAV+CUE][1.2GB]
- 华语流行S.H.E《12CD》2001~2010[APE+CUE][3.7GB]