classification
Title: Redundant calls made to comparison methods.
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.2, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: mark.dickinson Nosy List: brett.cannon, cjw296, mark.dickinson
Priority: normal Keywords: needs review

Created on 2009-09-22 15:37 by mark.dickinson, last changed 2009-11-15 14:00 by mark.dickinson. This issue is now closed.

Files
File name Uploaded Description Edit
issue6970.patch mark.dickinson, 2009-09-24 18:58
Messages (6)
msg93000 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-09-22 15:37
Here's some strange behaviour in py3k:

newton:py3k dickinsm$ ./python.exe
Python 3.2a0 (py3k:75015, Sep 22 2009, 16:25:12) 
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:
...     def __eq__(self, other):
...         print("In A.__eq__", self, other)
...         return NotImplemented
... 
>>> class B:
...     def __eq__(self, other):
...         print("In B.__eq__", self, other)
...         return NotImplemented
... 
>>> A() == B()
In A.__eq__ <__main__.A object at 0x34d030> <__main__.B object at 0x448210>
In B.__eq__ <__main__.B object at 0x448210> <__main__.A object at 0x34d030>
In B.__eq__ <__main__.B object at 0x448210> <__main__.A object at 0x34d030>
In A.__eq__ <__main__.A object at 0x34d030> <__main__.B object at 0x448210>
False

I'd expect to see only one call to A.__eq__ and one call to B.__eq__.

The cause seems to be that:

 - slot_tp_richcompare (in typeobject.c) makes two calls to half_richcompare,
   one with the original arguments and one with reverse arguments, *and*

 - do_richcompare (in object.c) also makes two calls to the tp_richcompare
   slot; again, one with the original arguments and one with the reversed
   arguments.

I tried removing the second block of slot_tp_richcompare (still in py3k);  
make and make test succeeded without any problems.  Removing this block does 
change behaviour though, so probably should not happen until 3.2, given that 
no-one appears to have reported the current behaviour actually causing any 
problems.

The duplicate calls also exist in 2.x;  figuring out a solution there (and 
being sure that the solution does the right thing) looks complicated, thanks 
to all the rich-compare/three-way-compare interactions.
msg93002 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-09-22 15:57
And here's an example from trunk:

Python 2.7a0 (trunk:75012M, Sep 22 2009, 11:16:39) 
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class A(object):
...     def __eq__(self, other):
...         print "A.__eq({!r}, {!r})".format(self, other)
...         return NotImplemented
... 
>>> A() == A()
A.__eq(<__main__.A object at 0x39f670>, <__main__.A object at 0x39f610>)
A.__eq(<__main__.A object at 0x39f610>, <__main__.A object at 0x39f670>)
A.__eq(<__main__.A object at 0x39f670>, <__main__.A object at 0x39f610>)
A.__eq(<__main__.A object at 0x39f610>, <__main__.A object at 0x39f670>)
A.__eq(<__main__.A object at 0x39f610>, <__main__.A object at 0x39f670>)
A.__eq(<__main__.A object at 0x39f670>, <__main__.A object at 0x39f610>)
False
msg93017 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2009-09-22 20:37
I say fix it in 3.2 and don't worry about 2.x unless you really want to. 
As you said, it's rather tricky to untangle all of that and no one has 
complained yet. Plus it is a semantic change.
msg93087 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-09-24 18:58
Here's a patch for py3k.  I'd appreciate it if some other committer could 
check it for sanity.
msg93902 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-10-12 19:16
Assigning to myself so this doesn't get forgotten.
msg95290 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-11-15 14:00
Committed to py3k in r76304.  Leaving trunk alone, as Brett suggested.
History
Date User Action Args
2009-11-15 14:00:27mark.dickinsonsetstatus: open -> closed
resolution: fixed
messages: + msg95290

stage: commit review -> resolved
2009-10-12 19:16:21mark.dickinsonsetassignee: mark.dickinson
messages: + msg93902
2009-09-24 19:04:46mark.dickinsonsetkeywords: + needs review, - patch
stage: needs patch -> commit review
2009-09-24 18:58:17mark.dickinsonsetfiles: + issue6970.patch
keywords: + patch
messages: + msg93087
2009-09-22 20:37:17brett.cannonsetnosy: + brett.cannon
messages: + msg93017
2009-09-22 15:57:27mark.dickinsonsetnosy: + cjw296
messages: + msg93002
2009-09-22 15:37:05mark.dickinsoncreate