与==比较时,具有相同id的对象是否总是相等的?

Are objects with the same id always equal when comparing them with ==?

如果我有两个对象 o1 和 o2,我们知道

id(o1) == id(o2)

returns .

那么,是否遵循

o1 == o2

或者情况并非总是如此?我正在研究的论文说情况并非如此,但在我看来它应该是真的!

这篇论文是对的。考虑以下因素。

class WeirdEquals:
    def __eq__(self, other):
        return False

w = WeirdEquals()
print("id(w) == id(w)", id(w) == id(w))
print("w == w", w == w)

输出是这样的:

id(w) == id(w) True
w == w False

id(o1) == id(o2) 并不意味着 o1 == o2

让我们看一下这个 Troll,它将 __eq__ 覆盖为始终 return False

>>> class Troll(object):
...     def __eq__(self, other):
...         return False
... 
>>> a = Troll()
>>> b = a
>>> id(a) == id(b)
True
>>> a == b
False

也就是说,在标准库中应该有 非常 几个 object-ids 匹配但 __eq__ 可以 return False 无论如何,感谢@MarkMüller 找到了一个很好的例子。

所以要么对象是疯狂的、非常特殊的(比如 nan),要么是并发问题困扰着你。考虑这个极端的例子,其中 Foo 有一个更合理的 __eq__ 方法('forgets' 检查 ids)并且 f is f 总是 True

import threading

class Foo(object):
    def __init__(self):
        self.x = 1

    def __eq__(self, other):
        return isinstance(other, Foo) and self.x == other.x

f = Foo()

class MutateThread(threading.Thread):
    def run(self):
        while True:
            f.x = 2
            f.x = 1

class CheckThread(threading.Thread):
    def run(self):
        i = 1
        while True:
            if not (f == f):
                print 'loop {0}: f != f'.format(i) 
            i += 1

MutateThread().start()
CheckThread().start()

输出:

$ python eqtest.py
loop 520617: f != f
loop 1556675: f != f
loop 1714709: f != f
loop 2436222: f != f
loop 3210760: f != f
loop 3772996: f != f
loop 5610559: f != f
loop 6065230: f != f
loop 6287500: f != f
...

不总是:

>>> nan = float('nan')
>>> nan is nan
True

或按照问题中的相同方式表述:

>>> id(nan) == id(nan)
True

但是

>>> nan == nan
False

NaN is a strange thing. Per definition it is not equal nor less or greater than itself. But it is the same object. More details why all comparisons have to return False in this SO question.