The documentation of this that comes to mind is spread over <https://docs.python.org/3.6/reference/datamodel.html#object.__eq__> and <https://docs.python.org/3.6/reference/expressions.html#value-comparisons>.
My understanding of how it works in general is that NotImplemented is just a simple object like None. It doesn’t have any special behaviour on its own. Similarly, if you call a special method like __eq__() manually, there is no fallback, you just get the NotImplemented object. The interpreter calls special methods like __eq__() when evaluating expressions, but the specific behaviour and how NotImplemented is interpreted varies subtly.
To evaluate a == b, if b’s class is a strict subclass of a’s class, b.__eq__(a) is tried first, otherwise a.__eq__(b) is tried first. If that call returns NotImplemented, the first fallback is to try the call. Failing that, the final fallback is the default behaviour for object() instances.
To evaluate a != b, there is another set of fallbacks in the chain, which is to try “not a.__eq__(b)”. So for __eq__(), the fallback depends on the class hierarchy, on whether a reversed call has already been made, and on whether you are evaluating == or !=.
The documentation for comparison operations was cleaned up a while ago (Issue 12067). But there is probably more room for improvement. I think the best thing would be to document the above sort of behaviour as being directly associated with operations like as == and !=, and only indirectly associated with the NotImplemented object and the __eq__() method.
|