Python中"a is b"与"id(a) == id(b)"有什么区别?

43 投票
1 回答
5080 浏览
提问于 2025-04-15 23:08

id()是Python里一个内置的函数,它会返回一个整数(或者长整数),这个数字在对象的整个生命周期内都是唯一的和不变的。

也就是说,每个对象都有一个独特的标识符。

is运算符则用来判断对象的身份。

简单来说,就是判断两个对象是不是同一个。

那么,为什么会出现两个对象的id相同,但用is检查却返回False的情况呢?下面有个例子:

>>> class Test():
...   def test():
...     pass
>>> a = Test()
>>> b = Test()
>>> id(a.test) == id(b.test)
True
>>> a.test is b.test
False

还有一个更让人困惑的例子:(接着上面的内容)

>>> b = a
>>> b is a
True
>>> b.test is a.test
False
>>> a.test is a.test
False

不过:

>>> new_improved_test_method = lambda: None
>>> a.test = new_improved_test_method
>>> a.test is a.test
True

1 个回答

66
>>> b.test is a.test
False
>>> a.test is a.test
False

每次你查找方法时,都会动态创建这些方法。这个函数对象(它总是同一个对象)实现了一个叫做描述符协议,它的 __get__ 方法会生成一个绑定的方法对象。通常情况下,没有两个绑定的方法会是同一个对象。

>>> id(a.test) == id(b.test)
True
>>> a.test is b.test
False

这个例子有点误导。第一个结果之所以是 True 只是巧合。a.test 创建了一个绑定的方法,但在计算 id(a.test) 后,它就被垃圾回收了,因为没有其他地方引用它。(注意你引用的文档中提到,id是“在这个对象的生命周期内是唯一且恒定的”(强调是我加的)。)b.test 恰好和之前的绑定方法有相同的 id,这是允许的,因为现在没有其他对象有相同的 id。

要注意的是,你应该很少使用 is,更少使用 idid(foo) == id(bar) 这个判断总是错误的。


关于你新的例子,希望你现在明白它的作用了:

>>> new_improved_test_method = lambda: None
>>> a.test = new_improved_test_method
>>> a.test is a.test
True

在这个情况下,我们并不是自动从类中的函数创建方法并绑定 self,返回绑定的方法对象。这里,你只是把一个函数存储为实例的属性。查找时没有什么特别的事情发生(描述符只有在你查找类属性时才会被调用),所以每次你查找这个属性时,得到的都是你存储的原始对象。

撰写回答