id
из Point
объектов различны, потому что они разные объекты и для них нет механизма кэширования / интернирования (что было бы неправильно, потому что они изменчивы).
==
работает, потому что при вызове ==
на Point
, вы звоните __eq__
, и это кодируется так:
def __eq__(self, other):
return id(self.x) == id(other.x) and id(self.y) == id(other.y)
так, это неправильно , но он работает большую частьвремя из-за интернирования целых чисел от -5 до 256 в CPython (дальнейшие тесты показывают, что он работает с большими значениями, но это не гарантировано).Пример счетчика:
a = 912
b = 2345
point = Point(a, b)
print(point == Point(456*2, b))
вы получите False
, даже если 456*2 == 912
Перепишите так, чтобы у вас не было сюрпризов с большими целыми числами:
def __eq__(self, other):
return self.x == other.x and self.y == other.y
Если вы удалите этот метод __eq__
, вы получите False
, так как в этом случае оператор Python по умолчанию ==
для неизвестного объекта имеет только идентификатор объекта для выполнения сравнений.
НоЦель ==
- сравнить объект с содержимым , а не с идентификаторами .Кодирование метода равенства, который проверяет идентичности, может привести к неожиданностям, как показано выше.
В Python, когда люди используют ==
, они ожидают, что объекты будут равны, если значения равны.Идентификационные данные - это деталь реализации, просто забудьте об этом.
(В предыдущих версиях Python вы также определили __ne__
, поскольку это не означает обратное __eq__
и может привести к странным ошибкам)
В двух словах : не используйте is
(помимо is None
идиома) или id
, если вы не пишете очень сложную низкоуровневую программу с кешированием и странными вещамиили при отладке вашей программы.