问题

遇到了一个现象,具体代码不贴了,大概是这样的:

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 and is 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 or is 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.

参考链接