Overloading operators on the rigth.

Alex Martelli aleaxit at yahoo.com
Thu Oct 14 10:00:28 CEST 2004

denis wendum <wendum.denis at pasdepourriels.edf.fr> wrote:
> > Here's how to find out:
> >
> > >>> class foo:
> > ...   def __getattr__(self, name):
> > ...     print 'looking for %r' % name
> > ...     raise AttributeError, name
> > ...
> > >>> f=foo()
> > >>> 12 < f
> > looking for '__gt__'
> > looking for '__coerce__'
> > looking for '__cmp__'
> Many thanks for your answer: you didn't just gave me the fish I asked but also
> showed me how to use a net for catching other fish.

You're welcome!  Python enjoys excellent "discoverability" (a term
copiously illustrated, by explanation and by example, in Eric Raymond's
excellent book "The Art of Unix Programming", highly recommended in both
paper and free-on-the-net form) -- it shews enough of its workings,
easily enough, that it's well worth doing some sniffing around, and the
ability to hack together a 4-line class that displays things with some
print statements in an interactive session is a good example.

Of course, I _was_ being a tad too glib here, which helps explain...:

> It seems I triggered a fierce debate with my question, but as far as I'm
> concerned your example worked perfectly.

...the "debate", which was in fact quite friendly, even for this
community's pretty good standards.  Summarizing, I half-cheated by using
an oldstyle class here, so that __getattr__ would indeed get called; a
newstyle class, while having just about the same behavior, does (...to
oversimply things a bit...) more processing at the time the class
statement is executed, it fills up a structure of internal 'slots', so
there is less "rooting around" at the time the < operator executes and
less of a chance to see the wheels in motion (there are of course plenty
of advantages in exchange, both conceptual and practical).  Moreover the
'__coerce__' concept is being de-emphasized and deprecated, so the
"lookup" order shifts slightly (coercion is now tried only as a "last
ditch", after 3-way comparison with __cmp__ rather than before).

This doesn't mean you can't do "sniffing around" in newstyle classes,
but it may require a different tack, such as:

>>> class foo(object):
...   def __gt__(self, other):
...     print 'doing gt'
...     return NotImplemented
...   def __cmp__(self, other):
...     print 'doing cmp'
...     return NotImplemented
>>> f=foo()
>>> 2<f
doing gt
doing cmp

The "return NotImplemented" may be seen as a way to implement a specific
comparison (say __gt__) in some cases while punting to more generic ways
implicitly -- you may use it to indicate to Python "I don't know how to
do this specific comparison in this specific method, so please try
something else [along the usual orders in which things are tried]"...


More information about the Python-list mailing list