Equality with __eq__
For ==, Python has an answer even when your class has no method for it. But it's probably not the answer you want:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
a = Point(1, 2)
b = Point(1, 2)
c = a
print(a == b)
print(a == c)
False
TrueWithout a method of its own, == asks whether the two are the very same object, as is does. a and c refer to the same point, but b is a different object, even though it has the same coordinates. To compare the contents, write the method __eq__:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
a = Point(1, 2)
b = Point(1, 2)
print(a == b)
print(a != b)
print(Point(3, 4) in [a, b, Point(3, 4)])
True
False
TrueTwo things come for free. When a class has __eq__ but no __ne__, Python works out != as the opposite of ==. And everything that compares items with == now works with points: in for lists, and the list methods count, index and remove.
Comparing with something else
__eq__ above expects other to be a point. Compared with anything else, say the string "1, 2", it would stop with an AttributeError, since a string has no x. A careful __eq__ first checks the type with isinstance, and returns False for anything that isn't a point:
def __eq__(self, other):
if not isinstance(other, Point):
return False
return self.x == other.x and self.y == other.y
A full set of comparisons
<= doesn't come from < and == automatically: write __le__ for it, and __ge__ for >=. (When one side has no method for an operator, Python tries the mirrored method of the other side: for b >= a it can use a.__le__(b). Still, writing a method for each operator you use is the clear way.) The new methods can be written with the ones you have. Software versions such as 3.12 and 3.14 are a good example. The major version, the first number, matters most, and the minor version only decides when the major versions are equal:
class Version:
def __init__(self, major, minor):
self.major = major
self.minor = minor
def __eq__(self, other):
return self.major == other.major and self.minor == other.minor
def __lt__(self, other):
if self.major != other.major:
return self.major < other.major
return self.minor < other.minor
def __le__(self, other):
return self < other or self == other
old = Version(3, 12)
new = Version(3, 14)
print(old < new)
print(new <= Version(3, 14))
print(Version(2, 99) < old)
True
True
TrueNote how __le__ uses self < other and self == other: inside the class, the operators call the class's own methods too.