问题
遇到了一个现象,具体代码不贴了,大概是这样的:
def find(x, nums):
ans = 0
for n in nums:
if x is n:
ans += 1
return ans
>>> find(10, range(20))
1
>>> find(300, range(200, 400))
0
查找一个数字在一个可迭代对象中出现的次数。但是上面的函数在 x 比较小时正常,一旦 x 偏大一些之后,这个结果就不符合预期了。看了好久,才发现问题,重点就是 is
和 ==
的区别。
深究
网络上随便一搜得到的结果大概是:
The == operator compares the values of both the operands and checks for value equality. Whereas is operator checks whether both the operands refer to the same object or not.
那么is
运算符究竟做了什么操作呢?它是一个比较运算符,根据文档的定义:
The operators
is
andis not
test for object identity:x is y
is true if and only if x and y are the same object.x is not y
yields the inverse truth value.
也就是说
>>> a is b
等价于
>>> id(a) == id(b)
那么 is
的使用场景是什么呢?根据文档:
Comparisons to singletons like None should always be done with
is
oris not
, never the equality operators.
也就是说,在比较一些单例模式的实例是应该使用 is
而不是 ==
。
但是,在如下的 case 中:
>>> a,b = 256, 256
>>> a is b
True
>>> a,b = 257, 257
>>> a is b
False
>>> 257 is 257
True
这是为什么呢?
原因是:Python 的底层实现中,缓存了 一部分整数来提高效率,这部分整数的范围是 [-5, 256],所以每次创建的这个范围内的整数的引用是,都指的是缓存的整数,而不是新创建的对象。
所以:Do not use is
to compare integers.
参考链接
- python – “is” operator behaves unexpectedly with integers – Stack Overflow
- 5. Expressions — Python 2.7.15 documentation
- svn.python.org/projects/python/trunk/Objects/intobject.c
- PEP 8 — Style Guide for Python Code | Python.org
- Python integer range -5 … 256 and identity comparison : Python
- Issue 1436243: Extend pre-allocated integers to cover [0, 255] – Python tracker