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.

Author steven.daprano
Recipients brett.cannon, docs@python, murali, steven.daprano
Date 2019-12-21.00:08:21
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1576886902.04.0.544865401241.issue39111@roundup.psfhosted.org>
In-reply-to
Content
The behaviour is correct: `==` should not raise, even if both objects' `__eq__` method returns NotImplemented.

I agree that the documentation needs improvement. Looking at the current version:

https://docs.python.org/3/library/constants.html#NotImplemented

it says:

    Note: When a binary (or in-place) method returns NotImplemented 
    the interpreter will try the reflected operation on the other 
    type (or some other fallback, depending on the operator). If all
    attempts return NotImplemented, the interpreter will raise an
    appropriate exception. Incorrectly returning NotImplemented will
    result in a misleading error message or the NotImplemented value
    being returned to Python code.


(1) In the case of `==` and `!=`, an exception is not raised even all relevant methods return NotImplemented.

The source code for PyObject_RichCompare in object.c says:

    /* If neither object implements it, provide a sensible default
       for == and !=, but raise an exception for ordering. */

and then falls back to object identity.

If we wanted to lawyer up, the current docs don't say that "some other fallback" is limited to Python dunder methods. But that's the strong impression it gives, and it is actively misleading in that there's no hint that the fallback includes a default notion of equality as object identity, built right into the interpreter itself.

Even Brett got this wrong: object.__eq__ can return NotImplemented, so it isn't a suitable final fallback:

    py> object.__eq__(o, None)
    NotImplemented


so I think these docs could do with some improvement. Based on the current docs, I too would expect equality to raise an exception for a class that defines `__eq__`  and `__ne__` to always return NotImplemented.


(2) The last sentence, about "incorrectly returning NotImplemented", confuses me. Why are we warning about that? If you incorrectly return any value, whether it is NotImplemented, True, False, None or 3.1415, it will result in a misleading error message or incorrect value being returned.

Is it perhaps meant to say "incorrectly *raising* NotImplemented"?

I'm reopening this for a doc enhancement. Unfortunately I can't use github for technical reasons, so can't do a PR, but I'll suggest an updated description for the first part. (I have no idea what to do for the second part.)

    When a binary (or in-place) method returns NotImplemented 
    the interpreter will try the reflected operation on the other 
    type (or some other fallback, depending on the operator). If all
    attempts return NotImplemented, the interpreter will fall back
    to object identity for `==` and `!=` or raise an appropriate
    exception for all other comparisons.
History
Date User Action Args
2019-12-21 00:08:22steven.dapranosetrecipients: + steven.daprano, brett.cannon, docs@python, murali
2019-12-21 00:08:22steven.dapranosetmessageid: <1576886902.04.0.544865401241.issue39111@roundup.psfhosted.org>
2019-12-21 00:08:21steven.dapranolinkissue39111 messages
2019-12-21 00:08:21steven.dapranocreate