heterogeneous comparisons in python3
- by Matt Anderson
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.