I use namedtuple classes a lot. I have been thinking today if there is a nice way to implement custom sorting for such a class, i.e. make the default sort key not the first element (then second, third, etc) of the namedtuple.
My first instinct was to implement __lt__ and __eq__ and let total_ordering do the rest (it fills out le, ne, gt, ge):
from collections import namedtuple
from functools import total_ordering
@total_ordering
class B(namedtuple('B', 'x y')):
    def __lt__(self, other):
        return self.y < other.y
However:
def test_sortingB():
    b1 = B(1, 2)
    b2 = B(2, 1)
    assert b2 < b1  # passes
    assert b2 <= b1  # fails
oh, right... total_ordering only fills out the other methods if they are missing. Since tuple/namedtuple has such methods, total_ordering isn't doing anything for me.
So I guess my options are
Suggestions on the best way to solve this?
OPTION 1. Use a mixin and apply the total_ordering to that
@total_ordering
class B_ordering(object):
    __slots__ = ()                 # see Raymond's comment
    def __lt__(self, other):
        return self.y < other.y
class B(B_ordering, namedtuple('B', 'x y')):
    pass
OPTION 2.  Make your own decorator based on total_ordering and just use that instead
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With