在 Python 中会用到对象之间比较, 可以用 ==, 也可以用 is . 但是它们的区别是什么呢?
is 比较的是两个实例对象是不是完全相同, 它们是不是同一个对象, 占用的内存地址是否相同. 莱布尼茨说过:"世界上没有两片完全相同的叶子", 这个 is 正是这样的比较, 比较是不是同一片叶子(即比较的 id 是否相同, 这 id 类似于人的身份证标识).
== 比较的是两个对象的内容是否相等, 即内存地址可以不一样, 内容一样就可以了. 这里比较的并非是同一片叶子, 可能叶子的种类或者脉络相同就可以了. 默认会调用对象的 __eq__()方法.
可以通过如下例子来区分比较下:
- >>> a = ["I", "love", "Python"]
- >>> b = a
- # a 的引用复制给 b, 在内存中其实是指向了用一个对象
- >>> b is a
- True
- >>> id(a)
- 46381384
- >>> id(b)
- 46381384
- # 当然, 内容也肯定是相等的
- >>> b == a
- True
可以发现 b 和 a 的内存地址是相同的, 它们指向同一块内存, 因而 is 和 == 的结果都为 True. 这是因为直接赋值都是赋值的引用, 是引用, 是引用, 重要的事情说三遍. 但如果不是通过引用赋值, 而是通过切片赋值呢?
- # b 通过切片操作重新分配了对象, 但是值和 a 相同
- >>> b = a[:]
- >>> b is a
- False
- >>> id(a)
- 48740680
- >>> id(b)
- 48740680
- >>> b == a # 但他们的值还是相等的
- True
新建对象之后, b 和 a 指向了不同的内存, 所以 b is a 的结果为 False, 而 b==a 的结果为 True. 在这里, 小编提一个问题, b[0] is a[0] 的结果呢?
答案是 True. 因为切片拷贝是浅拷贝, 列表中的元素并未重新创建. 不理解的同学请翻看之前的文章 Python 中的浅拷贝与深拷贝 http://mp.weixin.qq.com/s?__biz=MzAwOTQ4MzY1Nw==&mid=2247484029&idx=1&sn=17379d6fb685faf3435669e28d54d517&chksm=9b5fa69bac282f8d5b84a6cb9c93cb948b08d785ec4152d1fcdd75b94f734d7a43fc6a568a8a&scene=21#wechat_redirect .
通常, 我们关注的是值, 而不是内存地址, 因此 Python 代码中 == 出现的频率比 is 高. 但是什么时候用 is 呢?
is 与 == 相比有一个比较大的优势, 就是计算速度快, 因为它不能重载, 不用进行特殊的函数调用, 少了函数调用的开销而直接比较两个整数 id. 而 a == b 则是等同于 a.__eq__(b). 继承自 object 的 __eq__ 方法比较两个对象的 id, 结果与 is 一样. 但是多数 Python 的对象会覆盖 object 的 __eq__方法, 而定义内容的相关比较, 所以比较的是对象属性的值.
在变量和单例值之间比较时, 应该使用 is. 目前, 最常使用 is 的地方是判断对象是不是 None. 下面是推荐的写法:
a is None
判断不是 None 的推荐写法是:
a is not None
Python 会对比较小的整数对象进行缓存, 下次用的时候直接从缓存中获取, 所以 is 和 == 的结果可能相同:
- >>> a = 1
- >>> b = 1
- >>> a is b
- True
- >>> a == b
- True
而看一下另外一段代码:
- >>> a = 257
- >>> b = 257
- >>> a is b
- False
这是什么原因呢?
注意, Python 仅仅对比较小的整数对象进行缓存 (范围为范围[-5, 256]) 缓存起来, 而并非是所有整数对象. 需要注意的是, 这仅仅是在命令行中执行, 而在 Pycharm 或者保存为文件执行, 结果是不一样的, 这是因为解释器做了一部分优化.
总结
1,is 比较两个对象的 id 值是否相等, 是否指向同一个内存地址;
2,== 比较的是两个对象的内容是否相等, 值是否相等;
3, 小整数对象 [-5,256] 在全局解释器范围内被放入缓存供重复使用;
4,is 运算符比 == 效率高, 在变量和 None 进行比较时, 应该使用 is.
来源: http://www.bubuko.com/infodetail-2718259.html