Объекты с одинаковым идентификатором всегда равны при сравнении их с ==?
Если у меня есть два объекта o1 и o2, и мы знаем, что
id(o1) == id(o2)
возвращает true.
Тогда следует ли, что
o1 == o2
Или это не всегда так? В документе, над которым я работаю, говорится, что это не тот случай, но, на мой взгляд, это должно быть правдой!
Ответы
Ответ 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
...