homepage

This issue tracker has been migrated to GitHub , and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: delegation of `!=` to the right-hand side argument is not always done
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.4, Python 3.5
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: serhiy.storchaka Nosy List: Arfrever, benjamin.peterson, exarkun, flox, josh.r, martin.panter, python-dev, r.david.murray, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2014年05月01日 14:31 by exarkun, last changed 2022年04月11日 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
method-not-operator.patch martin.panter, 2015年01月11日 06:39 review
method-not-operator-2.patch serhiy.storchaka, 2015年01月24日 16:45 review
Messages (15)
msg217699 - (view) Author: Jean-Paul Calderone (exarkun) * (Python committer) Date: 2014年05月01日 14:31
$ ~/Projects/cpython/3.4/python -c '
class Foo(object):
 def __ne__(self, other):
 return "yup"
 def __eq__(self, other):
 return "nope"
class Bar(object):
 pass
 
print(object() != Foo(), object() == Foo())
print(Bar() != Foo(), Bar() == Foo())
'
yup nope
False nope
$
The output I would expect from this is
 yup nope
 yup nope
That is, even when the type of the left-hand argument is not a base class of the type of the right-hand argument, delegation to the right-hand argument is sensible if the left-hand argument does not implement the comparison.
Note that the output also demonstrates that this is already the behavior for `==`. Only `!=` seems to suffer from this issue.
msg217700 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2014年05月01日 14:40
That's because the implicit default __ne__ on Bar returns the opposite of __eq__.
msg217727 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2014年05月01日 21:18
Why would an subclass of object that doesn't redefine either __eq__ or __ne__ have a different behavior for inequality than object itself? Bar never defined __eq__, so it shouldn't have an implicit __ne__ any more than object itself does...
Saying that Bar has an implicit __ne__ that object doesn't is answering how this happens, but it's not a why; is there a reason why this should be the case, or is this a bug (either in spec or in code) that should be fixed?
msg217729 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2014年05月01日 21:41
The reason ``object() != Foo()`` "works" is that Foo is a subtype of object(), so the specialized __ne__ of Foo is called immediately without trying object.__ne__.
I don't know whether it's a bug.
msg217730 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014年05月01日 21:47
I don't think it's a bug. The subclass-goes-first behavior is very intentional. The implicit __ne__ returning the boolean inverse of __eq__ is what fooled me when I looked at it.
Or did you mean that following the subclass rule in the case where object is the other class is possibly suspect?
msg217731 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2014年05月01日 21:52
The subclass behavior is a red herring.
I meant maybe object.__ne__ should check if the other object has a __ne__ method before falling back on ``not object.__eq__()``.
msg217732 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014年05月01日 22:24
Oh, I see. Yes, that would seem more consistent.
msg233827 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015年01月11日 00:29
There is a bit of analysis of the object.__ne__() implementation in Issue 4395. If my understanding is correct, I think it is a bug that object.__ne__(self, other) evaluates "not self == other". It should evaluate "not self.__eq__(other)" instead, so that NotImplemented can be caught, allowing the reflected other.__ne__(self) method to be tried.
msg233837 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015年01月11日 06:39
This patch should fix the problem I think. Before the __ne__() implementation was calling the "==" operator; now it calls the __eq__() method instead.
Also includes extra test for Issue 4395 to avoid having conficting patches.
msg234618 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015年01月24日 15:31
Particular case of this bug:
>>> class A:
... def __eq__(self, other): return NotImplemented
... 
>>> A().__eq__(object())
NotImplemented
>>> A().__ne__(object())
True
The second result should be NotImplemented.
Martin's patch LGTM except few style nitpicks to tests.
msg234620 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015年01月24日 16:45
There are few incorrect implementations of __ne__ in the stdlib. Updated patch removes them. May be we should remove all implementations of __ne__ which are redundant now.
msg234700 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015年01月25日 22:31
I looked over your __ne__ removals from the library, and they all seem sensible to me.
msg234718 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2015年01月26日 08:07
New changeset e516badfd3b2 by Serhiy Storchaka in branch '3.4':
Issue #21408: The default __ne__() now returns NotImplemented if __eq__()
https://hg.python.org/cpython/rev/e516badfd3b2
New changeset 7e9880052401 by Serhiy Storchaka in branch 'default':
Issue #21408: The default __ne__() now returns NotImplemented if __eq__()
https://hg.python.org/cpython/rev/7e9880052401 
msg234720 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015年01月26日 08:16
Thank you for your contribution Martin.
msg235101 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2015年01月31日 10:24
New changeset 3603bae63c13 by Serhiy Storchaka in branch 'default':
Issue #23326: Removed __ne__ implementations. Since fixing default __ne__
https://hg.python.org/cpython/rev/3603bae63c13 
History
Date User Action Args
2022年04月11日 14:58:03adminsetgithub: 65607
2015年01月31日 10:24:05python-devsetmessages: + msg235101
2015年01月26日 08:16:19serhiy.storchakasetstatus: open -> closed
versions: + Python 3.5, - Python 3.3
messages: + msg234720

resolution: fixed
stage: commit review -> resolved
2015年01月26日 08:07:11python-devsetnosy: + python-dev
messages: + msg234718
2015年01月25日 22:31:40martin.pantersetmessages: + msg234700
2015年01月24日 16:45:38serhiy.storchakasetfiles: + method-not-operator-2.patch

messages: + msg234620
2015年01月24日 15:31:45serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg234618

assignee: serhiy.storchaka
stage: commit review
2015年01月24日 15:18:29serhiy.storchakalinkissue23268 dependencies
2015年01月11日 06:39:42martin.pantersetfiles: + method-not-operator.patch
keywords: + patch
messages: + msg233837
2015年01月11日 02:01:27Arfreversetnosy: + Arfrever
2015年01月11日 00:29:01martin.pantersetmessages: + msg233827
2015年01月10日 10:25:56martin.pantersetnosy: + martin.panter
2014年05月01日 23:34:33floxsetnosy: + flox
2014年05月01日 22:24:36r.david.murraysetmessages: + msg217732
2014年05月01日 21:52:06benjamin.petersonsetmessages: + msg217731
2014年05月01日 21:47:31r.david.murraysetnosy: + r.david.murray
messages: + msg217730
2014年05月01日 21:41:43benjamin.petersonsetmessages: + msg217729
2014年05月01日 21:18:01josh.rsetnosy: + josh.r
messages: + msg217727
2014年05月01日 14:40:38benjamin.petersonsetnosy: + benjamin.peterson
messages: + msg217700
2014年05月01日 14:31:27exarkuncreate

AltStyle によって変換されたページ (->オリジナル) /