Python中"a is b"与"id(a) == id(b)"有什么区别?
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
,更少使用 id
。id(foo) == id(bar)
这个判断总是错误的。
关于你新的例子,希望你现在明白它的作用了:
>>> new_improved_test_method = lambda: None
>>> a.test = new_improved_test_method
>>> a.test is a.test
True
在这个情况下,我们并不是自动从类中的函数创建方法并绑定 self,返回绑定的方法对象。这里,你只是把一个函数存储为实例的属性。查找时没有什么特别的事情发生(描述符只有在你查找类属性时才会被调用),所以每次你查找这个属性时,得到的都是你存储的原始对象。