views:

32

answers:

1

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.

A: 

Rather than "fixing" something the python 3.x community "fixed" in the global scope, you may try the approach of enabling your objects/types to sort properly. I'm not as familiar with python 3.x, but I'm sure there still is a __cmp__ method that you could override in a sub-class and fix so that comparisons would work. You could use that in combination with id() to restore the old broken behavior (which just sorted based on position in memory, id(), if my memory serves me correctly).

xyld