Подтвердить что ты не робот

Объекты с одинаковым идентификатором всегда равны при сравнении их с ==?

Если у меня есть два объекта o1 и o2, и мы знаем, что

id(o1) == id(o2)

возвращает true.

Тогда следует ли, что

o1 == o2

Или это не всегда так? В документе, над которым я работаю, говорится, что это не тот случай, но, на мой взгляд, это должно быть правдой!

4b9b3361

Ответ 1

Не всегда:

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

или формулируется так же, как в вопросе:

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

но

>>> nan == nan
False

NaN - это странная вещь. По определению оно не равно или меньше или больше самого. Но это тот же объект. Более подробно, почему все сравнения должны возвращать False в этот вопрос SO.

Ответ 2

Бумага правильная. Рассмотрим следующее.

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

Ответ 3

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

При этом в стандартной библиотеке должно быть очень мало примеров, где идентификаторы объектов, а __eq__ могут возвращать False в любом случае, kudos @MarkMüller для поиска хорошего примера.

Таким образом, либо объекты безумны, очень специальные (например, nan), либо concurrency укусы. Рассмотрим этот крайний пример, где Foo имеет более разумный метод __eq__ (который "забывает" проверять идентификаторы), а 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
...