0

Not sure the best way to title this question, but how can I override or perform min(a, b) or max(a, b) on objects of a class i made? I can override the gt and lt like below but I would like to override the min or max so that I'll be able to use something like max(a, b, c ,d). The class will have multiple property as well, but I think 2 for this example is sufficient.

class MyClass:
    def __init__(self, item1, item2):
        self.item1 = item1
        self.item2 = item2

    def __gt__(self, other):
        if isinstance(other, MyClass):
            if self.item1 > other.item1:
                return True
            elif self.item1 <= other.item1:
                return False
            elif self.item2 > other.item2:
                return True
            elif self.item2 <= other.item2:
                return False

    def __lt__(self, other):
        if isinstance(other, MyClass):
            if self.item1 < other.item1:
                return True
            elif self.item1 >= other.item1:
                return False
            elif self.item2 < other.item2:
                return True
            elif self.item2 >= other.item2:
                return False

Ex:

a = MyClass(2,3)
b = MyClass(3,3)

print(a > b)
# False

I tried overriding __cmp__ but that doesnt seem to work.

Would like to be able to do max(a, b) and return b object

Aqueous Carlos
  • 445
  • 7
  • 20
user1179317
  • 2,693
  • 3
  • 34
  • 62
  • You can already call `max(a, b, c, ...)` with an arbitrary number of arguments, and it'll return whichever is largest, by comparing them to each other. It uses `__gt__` and `__lt__` to do this, to the best of my knowledge. You can't override `max()` itself, unfortunately, because it's a built-in method and isn't bound to a specific class (though you could easily write your own method to do the same thing if you wanted). Is there a specific thing you want `max()` to do here that it doesn't do already, and if so could you give a clearer example? – Green Cloak Guy Nov 14 '18 at 03:29
  • (1) You are already returning `b` via `max(a, b)`. `max(a, b) is b` – Brad Solomon Nov 14 '18 at 03:31
  • 1
    (2) Consider `functools.total_ordering` – Brad Solomon Nov 14 '18 at 03:31
  • (3) `max(a, b, c ,d)` is also already valid. What specifically is wrong with what you've written now? – Brad Solomon Nov 14 '18 at 03:32
  • Im sorry, could have sworn it wasnt working right before. But it does seem to work fine as is. Thats so weird. My bad, do i delete this question then? Sorry for the trouble – user1179317 Nov 14 '18 at 03:37
  • Ah I remember now why it wasnt working before. I used a = MyClass(3, 4) and b = MyClass(3, 2) and did min(a, b) and was returning 'a'. The problem is because i have <= and >= for gt and lt respectively. – user1179317 Nov 14 '18 at 03:49
  • This appears to be working. Try `max(a,b)==b` which returns `True` – dawg Nov 14 '18 at 04:40
  • 1
    Don't forget the `return NotImplemented` for when the other object isn't an instance of the expected class. – user2357112 Nov 14 '18 at 05:32

1 Answers1

4

Just override the comparison magic methods.

class A(object):

    def __init__(self, value):
        self.value = value

    def __lt__(self, other):
        return self.value < other.value

    def __le__(self, other):
        return self.value <= other.value

    def __eq__(self, other):
        return self.value == other.value

    def __ne__(self, other):
        return self.value != other.value

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

    def __ge__(self, other):
        return self.value >= other.value

    def __str__(self):
        return str(self.value)

a = A(10)
b = A(20)
min(a, b)
MonstraG
  • 180
  • 2
  • 7
  • 3
    is there a shorter version ?, is it enough to just define for ex `__le__()` and `__ge__()` to use max or min ? – Pablo Jun 25 '20 at 03:10
  • Arrived here with your same question @Pablo, and there is functools.total_ordering for that (https://docs.python.org/3/library/functools.html#functools.total_ordering), leaving it here for future reference – Sebastian Yonekura Baeza Dec 06 '22 at 20:20