将它们与==进行比较时,具有相同id的对象是否始终相等?

时间:2016-01-04 21:13:16

标签: python equality

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

id(o1) == id(o2)

返回 true

然后,它是否遵循

o1 == o2

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

3 个答案:

答案 0 :(得分:129)

并非总是如此:

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

或以与问题相同的方式制定:

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

>>> nan == nan
False

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

答案 1 :(得分:59)

论文是对的。请考虑以下事项。

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

答案 2 :(得分:25)

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

让我们看一下Troll,它会覆盖__eq__并始终返回False

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

话虽如此,标准库中应该有非常的例子,其中object-id匹配,但__eq__无论如何都可以返回False,kudos @MarkMüller寻找一个很好的例子。

因此,无论是对象是疯狂的,非常特殊的(如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:
            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
...