Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is NotImplemented truthy in Python 3?

This question is spurred from the answers and discussions of this question. The following snippet shows the crux of the question:

>>> bool(NotImplemented)
True

The questions I have are the following:

  1. Why was it decided that the bool value of NotImplemented should be True? It feels unpythonic.
  2. Is there a good reason I am unaware of? The documentation seems to just say, "because it is".
  3. Are there any examples where this is used in a reasonable manner?

Reasoning behind why I believe it's unintuitive (please disregard the lack of best practice):

>>> class A:
...     def something(self):
...         return NotImplemented
...
>>> a = A()
>>> a.something()
NotImplemented
>>> if a.something():
...     print("this is unintuitive")
...
this is unintuitive

It seems an odd behavior that something with such a negative connotation (lack of implementation) would be considered truthy.

Relevant text from:

NotImplemented

Special value which should be returned by the binary special methods (e.g. __eq__(), __lt__(), __add__(), __rsub__(), etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g. __imul__(), __iand__(), etc.) for the same purpose. Its truth value is true.

— From the Python Docs

Edit 1

To clarify my position, I feel that NotImplemented being able to evaluate to a boolean is an anti-pattern by itself. I feel like an Exception makes more sense, but the prevailing idea is that the constant singleton was chosen for performance reasons when evaluating comparisons between different objects. I suppose I'm looking for convincing reasons as to why this is "the way" that was chosen.

like image 344
Julian Avatar asked Jan 10 '19 17:01

Julian


2 Answers

By default, an object is considered truthy (bool(obj) == True) unless its class provides a way to override its truthiness. In the case of NotImplemented, no one has ever provided a compelling use-case for bool(NotImplemented) to return False, and so <class 'NotImplementedType'> has never provided an override.

like image 186
chepner Avatar answered Oct 04 '22 22:10

chepner


As the accepted answer already explains, all classes in python are considered truthy (bool(obj) returns True) unless they specifically change that via Truth Value Testing. It makes sense in some cases to override that, like an empty list, 0, or False (see a good list here).

However there is no compelling case for NotImplemented to be falsy. It's a special value used by the interpreter, it should only be returned by special methods, and shouldn't reach regular python code.

Special value which should be returned by the binary special methods (e.g. __eq__(), __lt__(), __add__(), __rsub__(), etc.) to indicate that the operation is not implemented with respect to the other type.

Incorrectly returning NotImplemented will result in a misleading error message or the NotImplemented value being returned to Python code.

It's used by the interpreter to choose between methods, or to otherwise influence behaviour, as is the case with with the comparison operator == or bool() itself (it checks __bool__ first and then, if it returns NotImplemented, __len__).

Note that a NotImplementedError exception exists, presumably for when it actually is an error that an operation isn't implemented. In your specific example, something of class A should probably raise this exception instead.

like image 35
Ramon Avatar answered Oct 04 '22 22:10

Ramon