a == b 是假的,但 id(a) == id(b) 是真的?

Posted

技术标签:

【中文标题】a == b 是假的,但 id(a) == id(b) 是真的?【英文标题】:a == b is false, but id(a) == id(b) is true? 【发布时间】:2011-01-20 02:50:54 【问题描述】:

遇到以下情况:

>>> class A:
...     def __str__(self):
...             return "some A()"
... 
>>> class B(A):
...     def __str__(self):
...             return "some B()"
... 
>>> print A()
some A()
>>> print B()
some B()
>>> A.__str__ == B.__str__
False # seems reasonable, since each method is an object
>>> id(A.__str__)==id(B.__str__)
True # what?!

这是怎么回事?

【问题讨论】:

【参考方案1】:

以下作品:

>>> id(A.__str__.im_func) == id(A.__str__.im_func)
True
>>> id(B.__str__.im_func) == id(A.__str__.im_func)
False

【讨论】:

【参考方案2】:

在评估字符串id(A.__str__) == id(B.__str__) 时,会创建A.__str__,获取其ID,然后进行垃圾收集。然后B.__str__ 被创建,并且恰好到达与A.__str__ 之前完全相同的地址,因此它(在CPython 中)获得了相同的ID。

尝试将A.__str__B.__str__ 分配给临时变量,你会看到不同的东西:

>>> f = A.__str__
>>> g = B.__str__
>>> id(f) == id(g)
False

对于这种现象的一个更简单的例子,试试:

>>> id(float('3.0')) == id(float('4.0'))
True

【讨论】:

但是,为什么 >>> f = A.__str__ >>> id(f) == id(A.__str__) False @jldupont:Python 在运行时创建未绑定的方法A.__str__B.__str__。 users.rcn.com/python/download/Descriptor.htm 是一个很好的底层机制参考。 hmmm...那些垃圾能这么快被收集起来吗?我仍然不相信这种解释。 @jldupont,CPython 被引用,所以大多数东西都会立即被垃圾收集。这是对所发生情况的正确解释。 @jldupont:测试理论很容易!尝试创建 float 的子类 myfloat,并覆盖 __new____del__,以便它们正确记录调用。现在观察评估id(myfloat(1.0)) == id(myfloat(2.0)) 时的操作顺序。 (不过,对__del__ 的调用不一定直接对应于垃圾回收。)【参考方案3】:

对于我们这些被你的标题所吸引的人,确定一个方法是否被覆盖:

class A:
    def __str__(self):
        return "some A()"

    def strWasOverridden(self):
        return A.__str__ != self.__str__

【讨论】:

其实,没有。这总是正确的,因为方法上的实例永远不会等于类上的方法。

以上是关于a == b 是假的,但 id(a) == id(b) 是真的?的主要内容,如果未能解决你的问题,请参考以下文章

Python:将空字符串与False进行比较是假的,为什么?

为啥文档不存在。但所有时间 !snapshot.hasData 都是假的

八枚硬币 有一个是假的 用一个天平秤两次找出那个假的 怎么做

我招聘了一名程序员,试用期都过了,结果发现他学历是假的...

在C语言中a^b是啥意思啊

(x || !x) 啥时候是假的?