Python中的“a is b”和“id(a) == id(b)”有啥区别?

Posted

技术标签:

【中文标题】Python中的“a is b”和“id(a) == id(b)”有啥区别?【英文标题】:What is the difference between "a is b" and "id(a) == id(b)" in Python?Python中的“a is b”和“id(a) == id(b)”有什么区别? 【发布时间】:2011-02-23 18:31:51 【问题描述】:

id() 内置函数提供...

一个整数(或长整数),保证在其生命周期内对于此对象是唯一且恒定的。

is 运算符反而给出...

对象身份

那么为什么可能有两个对象具有相同的id 但将False 返回到is 检查?这是一个例子:

>>> 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

【问题讨论】:

对于一个实际的程序或元类绝地思维技巧,我需要这个,请注意。我在火车上很无聊,我试过了:) 我认为重要的问题是为什么a.test is a.test 是假的。一旦你知道其余的应该是有意义的...... 漏油事件很好,很漂亮,它很快就会来到你附近的一个城市!也许你应该组织一些聚会来庆祝它的到来! == 是完全独立的。这是一个 is 并不意味着相等的情况。 a = float('nan'); print a is a, a == a @Paul:我没有问a == b,我问的是id(a) == id(b) :) 【参考方案1】:
>>> b.test is a.test
False
>>> a.test is a.test
False

方法是在您每次查找时即时创建的。函数对象(始终是同一个对象)实现了descriptor protocol,它的__get__ 创建了绑定的方法对象。没有两个绑定方法通常是同一个对象。

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

这个例子具有欺骗性。第一个结果只是巧合Truea.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

在这种情况下,我们不会从类上的函数自动绑定自身并返回绑定的方法对象来动态创建方法。在这种情况下,您只需将函数存储为实例属性。查找时没有什么特别的事情发生(只有在查找类属性时才会调用描述符),所以每次查找属性时,都会得到存储的原始对象。

【讨论】:

"每次查找时都会动态创建方法。函数对象(始终是同一个对象)实现描述符协议,其__get__ 创建绑定方法对象。没有两个绑定方法通常是同一个对象。” 哈,这对我来说是新闻。不错!

以上是关于Python中的“a is b”和“id(a) == id(b)”有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

python中的赋值浅拷贝和深拷贝

浅谈python中的引用和拷贝问题

聊聊Python中的is和==

一文了解 Python 中的对象比较方法 is 和 == 及其本质

python中的内存机制

[py]python中的==和is的区别