Why return NotImplemented instead of raising NotImplementedError
It's because __lt__()
and related comparison methods are quite commonly used indirectly in list sorts and such. Sometimes the algorithm will choose to try another way or pick a default winner. Raising an exception would break out of the sort unless caught, whereas NotImplemented
doesn't get raised and can be used in further tests.
http://jcalderone.livejournal.com/32837.html
To summarise that link:
"
NotImplemented
signals to the runtime that it should ask someone else to satisfy the operation. In the expressiona == b
, ifa.__eq__(b)
returnsNotImplemented
, then Python triesb.__eq__(a)
. Ifb
knows enough to returnTrue
orFalse
, then the expression can succeed. If it doesn't, then the runtime will fall back to the built-in behavior (which is based on identity for==
and!=
)."
Why doesn't NotImplemented raise a TypeError?
When you return NotImplemented
you indicate that you do not know if __ne__
should return True
or False
.
Normally, Python will then swap the operands; if a != b
results in NotImplemented
, it'll try b != a
instead. That'll fail here too, since you use the same type on both sides of the operator. For the !=
operator, Python will then fall back to comparing their memory addresses, and these are not the same (two separate instances), so False is returned.
See the do_richcompare
C function for details.
You'll have to raise TypeError()
manually if that is your expected outcome.
Why is int raising a TypeError instead of NotImplemented?
Your understanding of the numeric model is correct:
>>> class Foob(object):
... def __add__(self, o): return 1
... def __radd__(self, o): return 2
...
>>> f = Foob()
>>> f + f
1
>>> f + 5
1
>>> 5 + f
2
Your __radd__
code must eventually be raising a TypeError
- possibly by calling int
's +
with an incorrect type. What's the stack trace look like?
is `__radd__` called if `__add__` raises `NotImplementedError`?
The behavior that triggers __radd__()
is not, in fact, a NotImplementedError
, but rather a special object called NotImplemented
:
>>> help(NotImplemented)
Help on NotImplementedType object:
class NotImplementedType(object)
| Methods defined here:
|
| __reduce__(...)
| Helper for pickle.
|
| __repr__(self, /)
| Return repr(self).
|
| ----------------------------------------------------------------------
| Static methods defined here:
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
A NotImplementedError
will still propagate as an error. However, returning the NotImplemented
object (rather than raising an error) will allow __radd__()
to trigger:
>>> class A:
... def __add__(self, other):
... raise NotImplementedError()
...
>>> class B:
... def __add__(self, other):
... print("__add__ was called")
... def __radd__(self, other):
... print("__radd__ was called")
...
>>> class C:
... def __add__(self, other):
... return NotImplemented
...
>>> a, b, c = A(), B(), C()
>>> b + a
__add__ was called
>>> a + b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __add__
NotImplementedError
>>> b + c
__add__ was called
>>> c + b
__radd__ was called
raise NotImplementedError NotImplementedError
Python 3.8 made a backwards-incompatible change to the asyncio
package used by Tornado. Applications that use Tornado on Windows with Python 3.8 must call asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
at the beginning of their main file/function. (as documented on the home page of tornadoweb.org)
Related Topics
How to Compare Dates in Django Templates
Why Do Attribute References Act Like This with Python Inheritance
Can You Give a Django App a Verbose Name for Use Throughout the Admin
How to Get Rid of Beautifulsoup User Warning
How to Bind the Enter Key to a Function in Tkinter
Overloaded Functions in Python
How to Create an Incrementing Filename in Python
How to Apply Itertools.Product to Elements of a List of Lists
Convert Pandas Dataframe to a Nested Dict
Matplotlib Scatterplot with Legend
Plotting Networkx Graph with Node Labels Defaulting to Node Name
How to Get 'Real-Time' Information Back from a Subprocess.Popen in Python (2.5)
Editing Workbooks with Rich Text in Openpyxl
Pandas Concat Generates Nan Values