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

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

id(o1) == id(o2) 

返回true

那么,它是否遵循这一点

 o1 == o2 

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

不总是:

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

或者按照与问题中相同的方式制定:

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

 >>> nan == nan False 

NaN是一件奇怪的事情。 根据定义,它不等于或小于或大于自身。 但它是同一个对象。 更多细节为什么所有的比较都必须在这个SO问题中返回False

这篇文章是对的。 考虑以下。

 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

让我们来看看这个覆盖__eq__总是返回False Troll

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

也就是说,标准库中的object-id匹配的例子应该是非常less的,但是__eq__无论如何都可以返回False ,Kudos @MarkMüllerfind了一个很好的例子。

因此,无论对象是疯了,非常特殊(如nan),或并发咬你。 考虑这个极端的例子, Foo有一个更合理的__eq__方法(忘记检查id), 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: fx = 2 fx = 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 ...