Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if an object is order-able in python?

How can I check if an object is orderable/sortable in Python?

I'm trying to implement basic type checking for the __init__ method of my binary tree class, and I want to be able to check if the value of the node is orderable, and throw an error if it isn't. It's similar to checking for hashability in the implementation of a hashtable.

I'm trying to accomplish something similar to Haskell's (Ord a) => etc. qualifiers. Is there a similar check in Python?

like image 219
reem Avatar asked Oct 27 '13 03:10

reem


2 Answers

If you want to know if an object is sortable, you must check if it implements the necessary methods of comparison.

In Python 2.X there were two different ways to implement those methods:

  1. cmp method (equivalent of compareTo in Java per example)

    __cmp__(self, other): returns >0, 0 or <0 wether self is more, equal or less than other

  2. rich comparison methods

    __lt__, __gt__, __eq__, __le__, __ge__, __ne__

    The sort() functions call this method to make the necessary comparisons between instances (actually sort only needs the __lt__ or __gt__ methods but it's recommended to implement all of them)

In Python 3.X the __cmp__ was removed in favor of the rich comparison methods as having more than one way to do the same thing is really against Python's "laws".

So, you basically need a function that check if these methods are implemented by a class:

# Python 2.X
def is_sortable(obj):
    return hasattr(obj, "__cmp__") or \
           hasattr(obj, "__lt__") or \
           hasattr(obj, "__gt__")

# Python 3.X
def is_sortable(obj):
    cls = obj.__class__
    return cls.__lt__ != object.__lt__ or \
           cls.__gt__ != object.__gt__

Different functions are needed for Python 2 and 3 because a lot of other things also change about unbound methods, method-wrappers and other internal things in Python 3.

Read this links you want better understanding of the sortable objects in Python:

  • http://python3porting.com/problems.html#unorderable-types-cmp-and-cmp

  • http://docs.python.org/2/howto/sorting.html#the-old-way-using-the-cmp-parameter

PS: this was a complete re-edit of my first answer, but it was needed as I investigated the problem better and had a cleaner idea about it :)

like image 107
abranches Avatar answered Oct 05 '22 23:10

abranches


Regrettably it is not enough to check that your object implements lt. numpy uses the '<' operator to return an array of Booleans, which has no truth value. SQL Alchemy uses it to return a query filter, which again no truth value. Ordinary sets uses it to check for a subset relationship, so that

set1 = {1,2}
set2 = {2,3}
set1 == set2
False
set1 < set2
False
set1 > set2
False

The best partial solution I could think of (starting from a single object of unknown type) is this, but with rich comparisons it seems to be officially impossible to determine orderability:

 if hasattr(x, '__lt__'):
     try:
         isOrderable = ( ((x == x) is True) and ((x > x) is False)
                         and not isinstance(x, (set, frozenset)) )
     except:
         isOrderable = False
 else:
     isOrderable = False
like image 26
user6015320 Avatar answered Oct 05 '22 21:10

user6015320