Johan Råde
Johan Råde

Reputation: 21418

How to handle mixed types when implementing comparison operators?

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

Upvotes: 5

Views: 427

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1124000

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.

Upvotes: 3

pcalcao
pcalcao

Reputation: 15990

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.

Upvotes: 3

Related Questions