container.___le___ can use only <=?

Neil Cerutti horpner at yahoo.com
Wed Dec 19 11:03:27 EST 2007


On 2007-12-15, Carl Banks <pavlovevidence at gmail.com> wrote:
> On Dec 15, 9:05 am, ceru... at tds.net wrote:
>> My reasoning is (I hope) that the container ought to support
>> every comparison operation supported by the contained objects.
>> This can be ensured by being careful in the implementation.
>
> I see what you're asking now.  Yep, probably a bad idea to use
> that shortcut.

I put together a test suite, and discovered that the built-in
list assumes that all contained object support __eq__, i.e., it
may call __eq__ while performing some other comparison, e.g.,
__gt__. This is contrary to the rule I was contemplating for
sequence comparisons in this thread.

>>> class Evil:
...   def __init__(self, i):
...     self.i = i
...   def __eq__(self, o):
...     raise RuntimeError
...   def __gt__(self, o):
...     if isinstance(o, Evil):
...       return self.i > o.i
...     return NotImplemented
...
>>> [Evil(1)] > [Evil(0)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __eq__
RuntimeError

This prompted inspection of listobject.c. After trying some
short-cuts for __ne__ and __eq__, list_richcompare iterates
through both lists until the first non-equal elements are found,
and then performs the correct comparison, or simply returns,
depending on if the lists were the same length.

Otherwise, the built-in list rich comparison follows the advice
posted in this thread, i.e., it uses only the comparison
operation being implemented to compare contained objects.

When implementing a mutable sequence in Python, the rule of thumb
seems to be "do as lists do," so as of the Python's current
implementation, there's a small limit on the perversity level of
the rich comparison operations of types contained in lists.

-- 
Neil Cerutti



More information about the Python-list mailing list