python 3's adoption
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Thu Jan 28 21:21:28 EST 2010
On Thu, 28 Jan 2010 17:38:23 -0800, mdj wrote:
> On Jan 29, 9:47 am, Paul Boddie <p... at boddie.org.uk> wrote:
>> On 27 Jan, 13:26, Xah Lee <xah... at gmail.com> wrote:
>>
>>
>>
>> > So, for practical reasons, i think a “key” parameter is fine. But
>> > chopping off “cmp” is damaging. When your data structure is complex,
>> > its order is not embedded in some “key”. Taking out “cmp” makes it
>> > impossible to sort your data structure.
>>
>> What would annoy me if I used Python 3.x would be the apparent lack of
>> the __cmp__ method for conveniently defining comparisons between
>> instances of my own classes. Having to define all the rich comparison
>> methods frequently isn't even as much fun as it sounds.
>
> OT, but you can always define the other operators in terms of a cmp and
> mix it in, restoring the original behaviour. Unfortunately it won't
> restore the original performance until someone comes to their senses and
> restores __cmp__
"Comes to their senses"?
There's nothing you can do with __cmp__ that you can't do better with
rich comparisons, and plenty that rich comparisons can do that __cmp__ is
utterly incapable of dealing with. __cmp__ is crippled since it can only
be used for defining classes where the operators < etc return flags. It
can't be used if you want to implement some other behaviour for the
operators. E.g. here's a silly example:
>>> class Silly(object):
... def __init__(self):
... self.link = None
... def __gt__(self, other):
... self.link = other
...
>>> x = Silly()
>>> x > Silly()
>>> x.link
<__main__.X object at 0xb7cda74c>
More importantly, __cmp__ is only suitable for classes that implement
total ordering. If you have a data type that does not have total
ordering, for example sets, you can't implement it using __cmp__.
E.g.:
>>> s = set([1, 2, 3, 4])
>>> t = set([3, 4, 5, 6])
>>> s < t
False
>>> s > t
False
>>> s == t
False
>>> cmp(s, t)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot compare sets using cmp()
Sets have partial ordering, and __cmp__ is simply not up to the job of
dealing with it.
Having two mechanisms for implementing comparisons is unnecessary. It
adds complications to the language that we are better off without. The
only advantage of the obsolete __cmp__ is that lazy programmers only need
to write one method instead of six. This is an advantage, I accept that
(hey, I'm a lazy programmer too, that's why I use Python!) but it's not a
big advantage. If you really care about it you can create a mixin class,
a decorator, or a metaclass to simplify creation of the methods. For
example, a quick and dirty decorator:
>>> def make_comparisons(cls):
... cls.__gt__ = lambda self, other: self.__cmp__(other) == 1
... cls.__ge__ = lambda self, other: self.__cmp__(other) >= 0
... cls.__eq__ = lambda self, other: self.__cmp__(other) == 0
... cls.__ne__ = lambda self, other: self.__cmp__(other) != 0
... cls.__le__ = lambda self, other: self.__cmp__(other) <= 0
... cls.__lt__ = lambda self, other: self.__cmp__(other) == -1
... return cls
...
>>> @make_comparisons
... class BiggerThanEverything(object):
... def __cmp__(self, other):
... return 1
...
>>> x = BiggerThanEverything()
>>> x > 1000
True
>>> x < 0
False
--
Steven
More information about the Python-list
mailing list