heterogeneous comparisons in python3

Posted by Matt Anderson on Stack Overflow See other posts from Stack Overflow or by Matt Anderson
Published on 2010-05-05T01:15:45Z Indexed on 2010/05/05 1:28 UTC
Read the original article Hit count: 299

Filed under:
|

I'm 99+% still using python 2.x, but I'm trying to think ahead to the day when I switch.

So, I know that using comparison operators (less/greater than, or equal to) on heterogeneous types that don't have a natural ordering is no longer supported in python3.x -- instead of some consistent (but arbitrary) result we raise TypeError instead. I see the logic in that, and even mostly think its a good thing. Consistency and refusing to guess is a virtue.

But what if you essentially want the python2.x behavior? What's the best way to go about getting it?

For fun (more or less) I was recently implementing a Skip List, a data structure that keeps its elements sorted. I wanted to use heterogeneous types as keys in the data structure, and I've got to compare keys to one another as I walk the data structure. The python2.x way of comparing makes this really convenient -- you get an understandable ordering amongst elements that have a natural ordering, and some ordering amongst those that don't.

Consistently using a sort/comparison key like (type(obj).__name__, obj) has the disadvantage of not interleaving the objects that do have a natural ordering; you get all your floats clustered together before your ints, and your str-derived class separates from your strs.

I came up with the following:

import operator

def hetero_sort_key(obj):
    cls = type(obj)
    return (cls.__name__+'_'+cls.__module__, obj)

def make_hetero_comparitor(fn):
    def comparator(a, b):
        try:
            return fn(a, b)
        except TypeError:
            return fn(hetero_sort_key(a), hetero_sort_key(b))
    return comparator

hetero_lt = make_hetero_comparitor(operator.lt)
hetero_gt = make_hetero_comparitor(operator.gt)
hetero_le = make_hetero_comparitor(operator.le)
hetero_ge = make_hetero_comparitor(operator.gt)

Is there a better way?

I suspect one could construct a corner case that this would screw up -- a situation where you can compare type A to B and type A to C, but where B and C raise TypeError when compared, and you can end up with something illogical like a > b, a < c, and yet b > c (because of how their class names sorted). I don't know how likely it is that you'd run into this in practice.

© Stack Overflow or respective owner

Related posts about python

Related posts about comparison