5

What is the most natural way to complete the following code?

import functools

@functools.total_ordering
class X:
    def __init__(self, a):
        self._a = a

    def __eq__(self, other):
        if not isinstance(other, X):
            return False
        return self._a == other._a

    def __lt__(self, other):
        if not isinstance(other, X):
            return ...                    // what should go here?
        return self._a < other._a

if __name__ == '__main__':
    s = [2, 'foo', X(2)]
    s.sort()
    print s

2 Answers 2

3

You can choose whatever feels natural to you; False means your instances always sort after other types, True and they'll be sorted before.

Alternatively, you can return NotImplemented (see the __lt__ and other comparison methods documentation) to signal the comparison is not supported:

def __lt__(self, other):
    if not isinstance(other, X):
        return NotImplemented
    return self._a < other._a

Quoting the documentation:

A rich comparison method may return the singleton NotImplemented if it does not implement the operation for a given pair of arguments. By convention, False and True are returned for a successful comparison. However, these methods can return any value, so if the comparison operator is used in a Boolean context (e.g., in the condition of an if statement), Python will call bool() on the value to determine if the result is true or false.

Sign up to request clarification or add additional context in comments.

2 Comments

Just returning False or True is not a good idea. Consider the case when you have another analogous class Y and do X('foo') < Y('bar') and Y('bar') > X('foo'). The results may not be consistent.
But returning NotImplemented does work. Then Python will use its own default ordering that is somewhat arbitrary but consistent.
3

My personal approach:

An exception.

There's no natural order between different types.

The official one: (choose this one, there should be)

Although I don't agree with that completely, the manual clearly states how it should be done:

http://docs.python.org/library/stdtypes.html#comparisons

Objects of different types, except different numeric types and different string types, never compare equal; such objects are ordered consistently but arbitrarily (so that sorting a heterogeneous array yields a consistent result). Furthermore, some types (for example, file objects) support only a degenerate notion of comparison where any two objects of that type are unequal. Again, such objects are ordered arbitrarily but consistently. The <, <=, > and >= operators will raise a TypeError exception when any operand is a complex number.

So basically... I would raise an exception, but the most pythonic way of doing the ordering would be to comply with the manual.

There should be one-- and preferably only one --obvious way to do it.

5 Comments

But Python does implement such an order. I can sort the list [2.3, 'foo', int].
1 > 'a string' is False, 1 < 'a string' is True.
Specifically, TypeError("can't compare {} to {}".format(type(self), type(other))).
It can be very practical to have an order between different types, maybe comparing class names will do?
I've edited my reply to state what the manual says. The exception is my personal view, but I do agree it can come in handy, and since there's a clear specification for that, it should be done "by the book".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.