Python 3 __cmp__ semantic change?
Arnaud Delobelle
arnodel at googlemail.com
Sun Nov 23 05:05:27 EST 2008
Steven D'Aprano <steve at REMOVE-THIS-cybersource.com.au> writes:
> On Sat, 22 Nov 2008 09:10:04 +0000, Arnaud Delobelle wrote:
>
>> That's not surprising. You're measuring the wrong things. If you read
>> what I wrote, you'll see that I'm talking about Fraction.__gt__ being
>> slower (as it is defined in terms of Fraction.__eq__ and
>> Fraction.__lt__) using when my 'totally_ordered' decorator.
>>
>> I haven't done any tests but as Fraction.__gt__ calls *both*
>> Fraction.__eq__ and Fraction.__lt__ it is obvious that it is going to be
>> roughly twice as slow.
>
>
> What's obvious to you and what's obvious to the Python VM are not
> necessarily the same thing. I believe you are worrying about the wrong
> thing.
All I was asserting was that using my decorator, Fraction.__gt__ would
be roughly twice as slow as Fraction.__eq__ or Fraction.__lt__. I was
not worried about it at all! Your tests below, although very
interesting, don't shed any light on this.
> (BTW, I think your earlier decorator had a bug, in that it failed to
> define __ne__ but then called "self != other".)
That would be true for Python 2.x but I'm explicitly writing code for
Python 3 here, which, IIRC, infers != correctly when you define ==. I
can't refer you to the docs because my internet access to some US sites
seems to be partly broken ATM, but here's a simple example:
Python 3.0rc1+ (py3k:66521, Sep 21 2008, 07:58:29)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:
... def __init__(self):
... self
...
>>>
>>> class A:
... def __init__(self, x):
... self.x = x
... def __eq__(self, other):
... return self.x == other.x
...
>>> a, b, c = A(1), A(1), A(2)
>>> a==b, b==c, c==a
(True, False, False)
>>> a!=b, b!=c, c!=a
(False, True, True)
>>>
> My tests suggest that relying on __cmp__ is nearly three times
> *slower* than your decorated class, and around four times slower than
> defining all the rich comparisons directly:
>
> $ python comparisons.py
> Testing FractionCmp... 37.4376080036
> Testing FractionRichCmpDirect... 9.83379387856
> Testing FractionRichCmpIndirect... 16.152534008
> Testing FractionDecoratored... 13.2626030445
>
> Test code follows. If I've made an error, please let me know.
[snip test code]
If anything these tests make a retroactive case for getting rid of
__cmp__ as it seems really slow. Even FractionRichCmpIndirect (which is
the same as applying my second totally_ordered decorator to FractionCmp)
is almost twice as fast as FractionCmp. I would guess it is because
when doing e.g.
a < b
The VM will first look for
a.__lt__(b)
and fail, wasting some time in the process. Then it would look for
a.__cmp__(b)
Whereas when __lt__ is explicitely defined, the first step always
succeeds.
--
Arnaud
More information about the Python-list
mailing list