Why does my equality method produce True when the 2 objects point and b point to 2 different objects in memory?
import math
def main():
point = Point(2, 3)
print(point == Point(2, 3))
b = Point(2, 3)
print(id(point), id(b))
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def distance_from_origin(self):
return math.hypot(self.x, self.y)
def __eq__(self, other):
return id(self.x) == id(other.x) and id(self.y) == id(other.y)
def __repr__(self):
return f"Point({self.x!r}, {self.y!r})"
def __str__(self):
return f"{self.x!r}, {self.y!r}"
if name == 'main': main()
id
of Point
objects are different, because they're different objects and there is no cache/interning mechanism for them (which would be wrong because they're mutable).
==
works because when invoking ==
on Point
, you call __eq__
and it's coded like this:
def __eq__(self, other):
return id(self.x) == id(other.x) and id(self.y) == id(other.y)
so, it's wrong, but it works most of the time because of interning of integers from -5 to 256 in CPython (further tests show that it works with bigger values but it's not guaranteed). Counter example:
a = 912
b = 2345
point = Point(a, b)
print(point == Point(456*2, b))
you'll get False
even if 456*2 == 912
Rewrite as this so you won't have surprises with big integers:
def __eq__(self, other):
return self.x == other.x and self.y == other.y
If you remove this __eq__
method, you'll get False
, as in that case, Python default ==
operator on an unknown object only has object identity to perform comparisons.
But the purpose of ==
is to compare object contents, not ids. Coding an equality method that tests identities can lead to surprises, as shown above.
In Python when people use ==
, they expect objects to be equal if values are equal. Identities are an implementation detail, just forget about it.
(Previous versions of Python require you do define __ne__
as well, as it's not automatically the inverse of __eq__
and can lead to strange bugs)
In a nutshell: don't use is
(besides is None
idiom) or id
unless you're writing a very complex low-level program with caching and weird stuff or when debugging your program.