metaclasses for type comparison

Simon Burton simonb at webone.com.au
Wed Sep 10 21:50:59 EDT 2003


In today's experiment, I was wondering if I could make the comparison
operators (<,<=,>=,>) work on classes (types) according to inheritance.

The idea is, for example, classes lower in the class hierarchy would be
less than (more specialized) than classes they inherit from.

class A(object):
  pass

class B(A):
  pass

B < A # should be True

In my first attempt I tried putting __lt__ into the class definition for A
and then assigning it as a staticmethod. This doesn't work, but something
was happening; <,<=,>=,> are still valid as applied to classes.

Because class is to instance as metaclass is to class, I found that the
place to put these methods is in the class' metaclass.

class MetaCMP(type):
  def __lt__(cls,other):
    for base in cls.__bases__:
      if type(base) != cls.__class__:
        continue
      if base <= other:
        return 1
    return 0

  def __le__(cls,other):
    if cls == other:
      return 1
    for base in cls.__bases__:
      if type(base) != cls.__class__:
        continue
      if base <= other:
        return 1
    return 0

  def __gt__(cls,other):
    for base in other.__bases__:
      if type(base) != cls.__class__:
        continue
      if cls >= base:
        return 1
    return 0

  def __ge__(cls,other):
    if cls == other:
      return 1
    for base in other.__bases__:
      if type(base) != cls.__class__:
        continue
      if cls >= base:
        return 1
    return 0

__metaclass__ = MetaCMP

Now, with the above code, we can replace a call to isinstance.

type( B() ) <= A # True

It seems natural enough to my math trained eye.

But now we have non-comparible objects, which confuses the sorting issue.

class C:
  pass

C < A # False
A < C # False

For example, if we wanted a "total" order ( always either X<=Y or Y<=X )
we could remove __ge__ and __gt__ from MetaCMP. It's not clear to me
exactly which comparison methods "list.sort" uses. (The ideal sort here is
the topological sort.)

I also thought about extending this order so that "B() <= A" would behave
the same way. It would be rather more strange. Is it so natural that an
instance is "smaller" than it's type? Perhaps; the instance can have
attributes that override it's type, which is reminiscent of some kinds of
inheritance.

Finally, the feature request. If "type" implemented these semantics for
comparison would it break existing code? Does anyone rely on "1<dict"
being True, or that we have a total order (one of "<","==" or ">" always
True) ? Another quandry is that one could just as naturally argue for the
reverse ordering.

Comments sought (can you guess what + might do to classes?).

Simon Burton.





More information about the Python-list mailing list