Connecting Tech Pros Worldwide Help | Site Map

Python 3 __cmp__ semantic change?

  #1  
Old November 20th, 2008, 09:25 PM
Johannes Bauer
Guest
 
Posts: n/a
Hello group,

I'm porting some code of mine to Python 3. One class has the __cmp__
operator overloaded, but comparison doesn't seem to work anymore with that:

Traceback (most recent call last):
File "./parse", line 25, in <module>
print(x < y)
TypeError: unorderable types: IP() < IP()

Was there some kind of semantic change?

Kind regards,
Johannes

--
"Meine Gegenklage gegen dich lautet dann auf bewusste Verlogenheit,
verlästerung von Gott, Bibel und mir und bewusster Blasphemie."
-- Prophet und Visionär Hans Joss aka HJP in de.sci.physik
<48d8bf1d$0$7510$5402220f@news.sunrise.ch>
  #2  
Old November 20th, 2008, 09:35 PM
Inyeol.Lee@gmail.com
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


On Nov 20, 1:18*pm, Johannes Bauer <dfnsonfsdu...@gmx.dewrote:
Quote:
Hello group,
>
I'm porting some code of mine to Python 3. One class has the __cmp__
operator overloaded, but comparison doesn't seem to work anymore with that:
>
Traceback (most recent call last):
* File "./parse", line 25, in <module>
* * print(x < y)
TypeError: unorderable types: IP() < IP()
>
Was there some kind of semantic change?
Overload __lt__ method.

Inyeol
  #3  
Old November 20th, 2008, 09:45 PM
Johannes Bauer
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Inyeol.Lee@gmail.com schrieb:
Quote:
On Nov 20, 1:18 pm, Johannes Bauer <dfnsonfsdu...@gmx.dewrote:
Quote:
>Hello group,
>>
>I'm porting some code of mine to Python 3. One class has the __cmp__
>operator overloaded, but comparison doesn't seem to work anymore with that:
>>
>Traceback (most recent call last):
> File "./parse", line 25, in <module>
> print(x < y)
>TypeError: unorderable types: IP() < IP()
>>
>Was there some kind of semantic change?
>
Overload __lt__ method.
Well, of course I could do that, but the python doc says:

"Called by comparison operations if rich comparison (see above) is not
defined."
http://www.python.org/doc/2.5.2/ref/customization.html

And my code works just fine with 2.5 - only on 3.0 it doesn't work
anymore. Why is that?

Regards,
Johannes

--
"Meine Gegenklage gegen dich lautet dann auf bewusste Verlogenheit,
verlästerung von Gott, Bibel und mir und bewusster Blasphemie."
-- Prophet und Visionär Hans Joss aka HJP in de.sci.physik
<48d8bf1d$0$7510$5402220f@news.sunrise.ch>
  #4  
Old November 20th, 2008, 09:45 PM
Christian Heimes
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Johannes Bauer wrote:
Quote:
Hello group,
>
I'm porting some code of mine to Python 3. One class has the __cmp__
operator overloaded, but comparison doesn't seem to work anymore with that:
__cmp__ is gone

Christian

  #5  
Old November 20th, 2008, 09:55 PM
Steve Holden
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Johannes Bauer wrote:
Quote:
Inyeol.Lee@gmail.com schrieb:
Quote:
>On Nov 20, 1:18 pm, Johannes Bauer <dfnsonfsdu...@gmx.dewrote:
Quote:
>>Hello group,
>>>
>>I'm porting some code of mine to Python 3. One class has the __cmp__
>>operator overloaded, but comparison doesn't seem to work anymore with that:
>>>
>>Traceback (most recent call last):
>> File "./parse", line 25, in <module>
>> print(x < y)
>>TypeError: unorderable types: IP() < IP()
>>>
>>Was there some kind of semantic change?
>Overload __lt__ method.
>
Well, of course I could do that, but the python doc says:
>
"Called by comparison operations if rich comparison (see above) is not
defined."
http://www.python.org/doc/2.5.2/ref/customization.html
>
And my code works just fine with 2.5 - only on 3.0 it doesn't work
anymore. Why is that?
Well the Python 2.5 documentation can't be regarded as a reliable guide
to what to expect in 3.0 ...

You will observe that __cmp__ no longer appears in the index:

http://docs.python.org/dev/3.0/genindex-_.html

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

  #6  
Old November 20th, 2008, 10:25 PM
Ben Finney
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Steve Holden <steve@holdenweb.comwrites:
Quote:
You will observe that __cmp__ no longer appears in the index:
>
http://docs.python.org/dev/3.0/genindex-_.html
I searched in vain for an official description of this changed
behaviour. Where can we find an official description of how
comparisons are different in Python 3.0?

--
\ “[Entrenched media corporations will] maintain the status quo, |
`\ or die trying. Either is better than actually WORKING for a |
_o__) living.†—ringsnake.livejournal.com, 2007-11-12 |
Ben Finney
  #7  
Old November 20th, 2008, 10:55 PM
Steve Holden
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Ben Finney wrote:
Quote:
Steve Holden <steve@holdenweb.comwrites:
>
Quote:
>You will observe that __cmp__ no longer appears in the index:
>>
>http://docs.python.org/dev/3.0/genindex-_.html
>
I searched in vain for an official description of this changed
behaviour. Where can we find an official description of how
comparisons are different in Python 3.0?
>
If it's not present then it would be worth reporting it as a 3.0 bug -
there's still time to get it in, as the release isn't due until early
December.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

  #8  
Old November 20th, 2008, 10:55 PM
Terry Reedy
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Ben Finney wrote:
Quote:
Steve Holden <steve@holdenweb.comwrites:
>
Quote:
>You will observe that __cmp__ no longer appears in the index:
>>
>http://docs.python.org/dev/3.0/genindex-_.html
>
I searched in vain for an official description of this changed
behaviour. Where can we find an official description of how
comparisons are different in Python 3.0?
I was going to say "look in "What's New", but the __cmp__ removal is
missing. So I filed
http://bugs.python.org/issue4372

  #9  
Old November 20th, 2008, 11:05 PM
Christian Heimes
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Terry Reedy wrote:
Quote:
I was going to say "look in "What's New", but the __cmp__ removal is
missing. So I filed
http://bugs.python.org/issue4372
The whatsnew section of Python 3.0 is still empty. Guido didn't had time
to write it. http://bugs.python.org/issue2306

  #10  
Old November 20th, 2008, 11:45 PM
Johannes Bauer
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Steve Holden schrieb:
Quote:
If it's not present then it would be worth reporting it as a 3.0 bug -
there's still time to get it in, as the release isn't due until early
December.
Seems it was removed on purpose - I'm sure there was a good reason for
that, but may I ask why? Instead of the sleek __cmp__ function I had
earlier, I now have code like:


def __lt__(self, other):
return self.__cmp__(other) < 0

def __le__(self, other):
return self.__cmp__(other) < 0

def __gt__(self, other):
return self.__cmp__(other) 0

def __ge__(self, other):
return self.__cmp__(other) >= 0

Does anyone know the reason why __cmp__ was discarded?

Kind regards,
Johannes

--
"Meine Gegenklage gegen dich lautet dann auf bewusste Verlogenheit,
verlästerung von Gott, Bibel und mir und bewusster Blasphemie."
-- Prophet und Visionär Hans Joss aka HJP in de.sci.physik
<48d8bf1d$0$7510$5402220f@news.sunrise.ch>
  #11  
Old November 20th, 2008, 11:55 PM
Terry Reedy
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Christian Heimes wrote:
Quote:
Terry Reedy wrote:
Quote:
>I was going to say "look in "What's New", but the __cmp__ removal is
>missing. So I filed
>http://bugs.python.org/issue4372
>
The whatsnew section of Python 3.0 is still empty. Guido didn't had time
to write it. http://bugs.python.org/issue2306
What's New in Python 3.0 is incomplete but definitely not empty, and it
is part of the doc set.

  #12  
Old November 21st, 2008, 12:05 AM
skip@pobox.com
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?



JohannesSeems it was removed on purpose - I'm sure there was a good
Johannesreason for that, but may I ask why?

Start here:

http://www.mail-archive.com/python-3.../msg11474.html

Also, a comment to this blog post suggests creating a CmpMixin:

http://oakwinter.com/code/porting-setuptools-to-py3k/

Skip
  #13  
Old November 21st, 2008, 12:25 AM
Terry Reedy
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Johannes Bauer wrote:
Quote:
Steve Holden schrieb:
>
Quote:
>If it's not present then it would be worth reporting it as a 3.0 bug -
>there's still time to get it in, as the release isn't due until early
>December.
>
Seems it was removed on purpose - I'm sure there was a good reason for
that, but may I ask why? Instead of the sleek __cmp__ function I had
earlier, I now have code like:
>
>
def __lt__(self, other):
return self.__cmp__(other) < 0
>
def __le__(self, other):
return self.__cmp__(other) < 0
>
def __gt__(self, other):
return self.__cmp__(other) 0
>
def __ge__(self, other):
return self.__cmp__(other) >= 0
>
Does anyone know the reason why __cmp__ was discarded?
See previous threads, including recent one about sorting.

  #14  
Old November 21st, 2008, 01:05 AM
George Sakkis
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


On Nov 20, 6:58*pm, s...@pobox.com wrote:
Quote:
* * JohannesSeems it was removed on purpose - I'm sure there was a good
* * Johannesreason for that, but may I ask why?
>
Start here:
>
* * http://www.mail-archive.com/python-3.../msg11474.html
>
Also, a comment to this blog post suggests creating a CmpMixin:
>
* *http://oakwinter.com/code/porting-setuptools-to-py3k/
>
Skip
Dropping __cmp__ without providing implicit or at least easy explicit
[1] total ordering is (was?) a mistake; it opens the door to subtle
bugs or redundant boilerplate code.

[1] E.g. http://code.activestate.com/recipes/576529/
  #15  
Old November 21st, 2008, 09:15 AM
Duncan Booth
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Johannes Bauer <dfnsonfsduifb@gmx.dewrote:
Quote:
Seems it was removed on purpose - I'm sure there was a good reason for
that, but may I ask why? Instead of the sleek __cmp__ function I had
earlier, I now have code like:
>
>
def __lt__(self, other):
return self.__cmp__(other) < 0
>
def __le__(self, other):
return self.__cmp__(other) < 0
I hope you actually have <= here.
Quote:
>
def __gt__(self, other):
return self.__cmp__(other) 0
>
def __ge__(self, other):
return self.__cmp__(other) >= 0
>
Does anyone know the reason why __cmp__ was discarded?
I think it was because __cmp__ was the backward compatible fallback for
the newer rich comparison methods and Python 3 cleans up a lot of stuff
left in just for backward compatibility. In this case it is a cleanup
too far as in most cases (i.e. those cases where you don't need the full
complexity of the rich comparisons) __cmp__ is a much simpler solution.

See http://mail.python.org/pipermail/pyt...ch/034073.html
for Guido's original thoughts. Also, once upon a time pep-3000 referred
to the removal of __cmp__ but I can't find it in any of the current
peps. See
http://mail.python.org/pipermail/pyt...st/042959.html
and
http://mail.python.org/pipermail/pyt...st/042972.html
where the reference to removal of __cmp__ became "Comparisons other than
``==`` and ``!=`` between disparate types will raise an exception unless
explicitly supported by the type" and the reference to Guido's email
about removing __cmp__ was also removed.


--
Duncan Booth http://kupuguy.blogspot.com
  #16  
Old November 21st, 2008, 03:45 PM
Hyuga
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


On Nov 21, 4:09*am, Duncan Booth <duncan.bo...@invalid.invalidwrote:
Quote:
Johannes Bauer <dfnsonfsdu...@gmx.dewrote:
Quote:
Seems it was removed on purpose - I'm sure there was a good reason for
that, but may I ask why? Instead of the sleek __cmp__ function I had
earlier, I now have code like:
>
Quote:
def __lt__(self, other):
* * *return self.__cmp__(other) < 0
>
Quote:
def __le__(self, other):
* * *return self.__cmp__(other) < 0
>
I hope you actually have <= here.
>
>
>
Quote:
def __gt__(self, other):
* * *return self.__cmp__(other) 0
>
Quote:
def __ge__(self, other):
* * *return self.__cmp__(other) >= 0
>
Quote:
Does anyone know the reason why __cmp__ was discarded?
>
I think it was because __cmp__ was the backward compatible fallback for
the newer rich comparison methods and Python 3 cleans up a lot of stuff
left in just for backward compatibility. In this case it is a cleanup
too far as in most cases (i.e. those cases where you don't need the full
complexity of the rich comparisons) __cmp__ is a much simpler solution.
>
Seehttp://mail.python.org/pipermail/python-dev/2003-March/034073.html
for Guido's original thoughts. Also, once upon a time pep-3000 referred
to the removal of __cmp__ but I can't find it in any of the current
peps. Seehttp://mail.python.org/pipermail/python-checkins/2004-August/042959.html
andhttp://mail.python.org/pipermail/python-checkins/2004-August/042972.html
where the reference to removal of __cmp__ became "Comparisons other than
``==`` and ``!=`` between disparate types will raise an exception unless
explicitly supported by the type" and the reference to Guido's email
about removing __cmp__ was also removed.
Guido's primary argument for removing it seems to be that the code for
supporting both __cmp__ and the rich comparisons is "hairy" and that
it felt really satisfying to remove. I don't think that's a good
enough argument. It was hairy because there are a lot of cases to
check, but I wouldn't say it was crufty. It made sense, and the way
it worked seemed logical enough. I never ran into any problems with
it. And by and far the most common case is to implement some total
ordering for a class.

Now, as has been pointed out, all you really need to define total
ordering, at least for sorting, is __eq__ and __lt__, which isn't too
bad. But you still lose the ability to make any other sort of
comparison without implementing all the other comparison operators
too.

Perhaps the code could be made somewhat simpler like this: If rich
comparisons are defined, use those and *only* those operators that are
defined, and don't try to fall back on __cmp__ otherwise. If no rich
comparisons are defined, just look for __cmp__.
  #17  
Old November 21st, 2008, 05:35 PM
Arnaud Delobelle
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


Hyuga <hyugaricdeau@gmail.comwrites:
Quote:
On Nov 21, 4:09*am, Duncan Booth <duncan.bo...@invalid.invalidwrote:
Quote:
>Johannes Bauer <dfnsonfsdu...@gmx.dewrote:
Quote:
Seems it was removed on purpose - I'm sure there was a good reason for
that, but may I ask why? Instead of the sleek __cmp__ function I had
earlier, I now have code like:
>>
Quote:
def __lt__(self, other):
* * *return self.__cmp__(other) < 0
>>
Quote:
def __le__(self, other):
* * *return self.__cmp__(other) < 0
>>
>I hope you actually have <= here.
>>
>>
>>
Quote:
def __gt__(self, other):
* * *return self.__cmp__(other) 0
>>
Quote:
def __ge__(self, other):
* * *return self.__cmp__(other) >= 0
>>
Quote:
Does anyone know the reason why __cmp__ was discarded?
>>
>I think it was because __cmp__ was the backward compatible fallback for
>the newer rich comparison methods and Python 3 cleans up a lot of stuff
>left in just for backward compatibility. In this case it is a cleanup
>too far as in most cases (i.e. those cases where you don't need the full
>complexity of the rich comparisons) __cmp__ is a much simpler solution.
>>
>Seehttp://mail.python.org/pipermail/python-dev/2003-March/034073.html
>for Guido's original thoughts. Also, once upon a time pep-3000
>referred to the removal of __cmp__ but I can't find it in any of the
>current peps. See
>http://mail.python.org/pipermail/pyt...st/042959.html
>and
>http://mail.python.org/pipermail/pyt...st/042972.html
>where the reference to removal of __cmp__ became "Comparisons other
>than ``==`` and ``!=`` between disparate types will raise an
>exception unless explicitly supported by the type" and the reference
>to Guido's email about removing __cmp__ was also removed.
>
Guido's primary argument for removing it seems to be that the code for
supporting both __cmp__ and the rich comparisons is "hairy" and that
it felt really satisfying to remove. I don't think that's a good
enough argument. It was hairy because there are a lot of cases to
check, but I wouldn't say it was crufty. It made sense, and the way
it worked seemed logical enough. I never ran into any problems with
it. And by and far the most common case is to implement some total
ordering for a class.
>
Now, as has been pointed out, all you really need to define total
ordering, at least for sorting, is __eq__ and __lt__, which isn't too
bad. But you still lose the ability to make any other sort of
comparison without implementing all the other comparison operators
too.
As classes can be decorated in Python 3, you can write a decorator to
make a class totally ordered. Here is a very simplified proof of
concept such decorator:

def totally_ordered(cls):
if not hasattr(cls, '__gt__'):
def gt(self, other):
return self != other and not self < other
cls.__gt__ = gt
# Do the same with __le__, __ge__
return cls


@totally_ordered
class Fraction:
def __init__(self, num, den=1):
assert den 0, "denomintator must be 0"
self.num = num
self.den = den
def __eq__(self, other):
return self.num*other.den == self.den*other.num
def __lt__(self, other):
return self.num*other.den < self.den*other.num
Quote:
Quote:
Quote:
>>q12=Fraction(1, 2)
>>q23=Fraction(2, 3)
>>q12 < q23
True
Quote:
Quote:
Quote:
>>q12 q23
False

Granted it's not as efficient as a __cmp__ function.

--
Arnaud
  #18  
Old November 22nd, 2008, 01:15 AM
Steven D'Aprano
Guest
 
Posts: n/a

re: Python 3 __cmp__ semantic change?


On Fri, 21 Nov 2008 17:26:21 +0000, Arnaud Delobelle wrote:

[...]
Quote:
As classes can be decorated in Python 3, you can write a decorator to
make a class totally ordered. Here is a very simplified proof of
concept such decorator:
>
def totally_ordered(cls):
if not hasattr(cls, '__gt__'):
def gt(self, other):
return self != other and not self < other
cls.__gt__ = gt
# Do the same with __le__, __ge__
return cls
>
>
@totally_ordered
class Fraction:
def __init__(self, num, den=1):
assert den 0, "denomintator must be 0" self.num = num
self.den = den
def __eq__(self, other):
return self.num*other.den == self.den*other.num
def __lt__(self, other):
return self.num*other.den < self.den*other.num
>
Quote:
Quote:
>>>q12=Fraction(1, 2)
>>>q23=Fraction(2, 3)
>>>q12 < q23
True
Quote:
Quote:
>>>q12 q23
False
>
Granted it's not as efficient as a __cmp__ function.
What makes you say that? What do you mean by "efficient"? Are you talking
about memory footprint, runtime speed, disk-space, programmer efficiency,
algorithmic complexity, or something else?

As I see it, a __cmp__ method would be written something like this:

def __cmp__(self, other):
return cmp(self.num*other.den, self.den*other.num)

which presumably would save you a trivial amount of source code (and
hence memory footprint, disk-space and programmer efficiency), but the
algorithmic complexity is identical and the runtime speed might even be
trivially slower due to the extra function call.

If your major concern is to reduce the amount of repeated code in the
methods, then there's no reason why you can't write a __cmp__ method as
above and then call it from your rich comparisons:

def __eq__(self, other):
return self.__cmp__(other) == 0
def __lt__(self, other):
return self.__cmp__(other) < 0

and if you really want to be concise:

__gt__ = lambda s, o: s.__cmp__(o) 0
__ge__ = lambda s, o: s.__cmp__(o) >= 0
__le__ = lambda s, o: s.__cmp__(o) <= 0





--
Steven
Closed Thread