意外的 ID 方法行为

4
简单来说,为什么这段代码返回的是False而不是True:
a = 10
print(id(a) is id(a)) # why false?

id()返回整数,相同的整数变量指向相同的整数对象。那么为什么它返回false呢?与以下代码有何不同:

a = 10
b = 10
print(a is b) # it returns True

感谢解释。


“同一整数变量指向同一整数对象”——你怎么知道的?想想看:这在Python解释器中如何高效实现?这将可能需要缓存数十亿个对象……以千兆字节的内存代价。 - Konrad Rudolph
2个回答

2

因为,虽然这是真的,

a is a

id(a) 是一个大整数,不能通过 is 进行比较

>>> a = 10
>>> print(id(a) is id(a))
False
>>> print(id(a),id(a))
(44337068, 44337068)
>>>

请查看https://docs.python.org/2/c-api/int.html#c.PyInt_FromLong以了解哪些整数通过is进行比较 - 但请记住,这是一个实现细节,因此不要依赖它(始终使用==来比较整数):

>>> a = 256
>>> b = 256
>>> a is b
True
>>> a = 257
>>> b = 257
>>> a is b
False

(来自"is"运算符在整数上的行为不符合预期)

进一步激励我们始终使用==的原因如下:

a = 300
b = 300
print(a is b)
print(a is 300)
def c(a): return a is 300
def d(a): return a is b
print(c(a))
print(d(a))

当被保存到文件并运行时,打印出TrueTrueFalseTrue...。

难道不是因为 is 运算符检查它们是否引用相同的对象,而不是相等性吗?因为 44337068 is 44337068 是 True。 - dan-klasson
@dan-klasson 是的,但是在Python中,same-object仅适用于小整数(因为它们被缓存)。正如您所展示的那样,对于常量(在同一表达式中),它也是正确的,但是44337068 is 44337067+1是错误的。 - thebjorn
有趣的事情是,如果你在使用Python控制台: `>>> a = 300
b = 300 a is b False` 但是,如果你在任何IDE(如PyCharm、VSC)中使用相同的Python二进制解释器运行它,你会得到True。为什么会这样呢?
- Paweł Bąkiewicz
@PawełBąkiewicz,这是因为is未定义整数的相等性,如果您尝试,您将得到令人惊讶的结果。我已经扩展了我的答案,并提供了更多示例。 - thebjorn

0

如果你尝试做,例如

 print(str(id(id(a))) + " " + str(id(id(a))))
In [54]: print(str(id(id(a))) + " " + str(id(id(a))))
2460780951888 2460780951888

In [55]: print(str(id(id(a))) + " " + str(id(id(a))))
2460780951472 2460780951472

In [56]: print(str(id(id(a))) + " " + str(id(id(a))))
2460782062320 2460782062320

In [57]: print(str(id(id(a))) + " " + str(id(id(a))))
2460780951888 2460780951888

In [58]: print(str(id(id(a))) + " " + str(id(id(a))))
2460782473392 2460782475664

每次都会返回一个新的大整数id

正如@thebjorn所提到的,Python解释器不会缓存大整数,只有在CPython实现中介于-5和256之间的整数始终存在。

每次引用大整数时,都会为其创建一个新对象,而对于小整数,同一对象将继续被使用(作为优化),但是不能保证在所有Python实现中都保持这种情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接