1

I have a Python class like this:

@dataclass
class Person:
    name: str
    relatives: Iterable['Person']

I want to use the name attribute for all comparisons, so that Person objects are sorted alphabetically by default. Hence, I override the __gt__() method like this (as described in the documentation):

    def __gt__(self, other):
        return self.name > other.name

This actually resolves my initial task, I can do e.g.:

p1=Person("test1", relatives=[])
p2=Person("test2", relatives=[])
sorted([p1, p2])
Out[4]: [Person(name='test1', relatives=[]), Person(name='test2', relatives=[])]

As well as this:

p1>p2
Out[5]: False
p1<p2
Out[6]: True

I understand that I don't have to implement all operators:

__lt__() and __gt__() are each other’s reflection, __le__() and __ge__() are each other’s reflection, and __eq__() and __ne__() are their own reflection.

For equality comparison, however, I still have to override __eq__(other) explicitly:

    def __eq__(self, other):
        return isinstance(other, Person) and self.name == other.name

Is there a way to implement this in a more concise way? I would envision some way to tell the interpreter 'use attribute name for all comparisons!'.

Carsten
  • 1,912
  • 1
  • 28
  • 55

1 Answers1

4

If providing __eq__ and at least 1 of rich comparison is okay in your case you might use functools.total_ordering decorator, like so:

import functools
@functools.total_ordering
class Name:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return self.name
    def __eq__(self, other):
        return self.name == other.name
    def __gt__(self, other):
        return self.name > other.name
a = Name("a")
b = Name("b")
print(a<b)
print(a<=b)
print(b>=a)

output

True
True
True

If this is not accepable in your case you would need to prepare own decorator to use, for discussion of decorating class see How to decorate a class

Daweo
  • 31,313
  • 3
  • 12
  • 25
  • Great, this decorator looks exactly what I have been looking for! My IDE (PyCharm) still claims that the object does not implement `SupportsLessThanT` when I do, for instance, `min(p1, p1)`, but that might be a PyCharm rather than a Python issue. – Carsten May 31 '21 at 12:47