On Sat, Jun 19, 2021 at 03:30:05AM -, wyz2...@163.com wrote:
> Python raises TypeError when NotImplemented is returned from __add__,
> __invert__ etc. and __radd__ etc. aren't available.
Roughly correct. It's more complex than that.
> However, this disallows the customization of error messages.
Given a binary operator like `+`, there are two objects involved. Which
one do you think should get to customize the error message if neither
object handles the plus operator?
We can't customize error messages for syntax errors, attribute errors,
import errors, value errors, etc. I'm not sure that type errors are
special enough that they need to be customized.
> For example, in Python 3.8, __float__ etc. were removed from complex
> to allow methods like __rfloat__.
Are you sure about that? This is in 3.9:
>>> complex.__float__
>>> complex.__rfloat__
Traceback (most recent call last):
File "", line 1, in
AttributeError: type object 'complex' has no attribute '__rfloat__'
> But this makes abs(z) undiscoverable for many users.
The set of people who know about complex numbers but not about using
`abs(z)` to get the magnitude of a complex number is surely very small.
> The original error message is very helpful.
We have to go all the way back to Python 2.5 to get a hint to use
abs(z):
>>> float(1+2j)
Traceback (most recent call last):
File "", line 1, in
TypeError: can't convert complex to float; use abs(z)
I don't think Python 3 has ever given such a hint: the oldest version I
have installed, 3.2, doesn't.
In any case, if we really think this is important, we could special case
complex numbers. But I don't think it is important.
Remember that it isn't mandatory for error messages to explain
everything the caller needs to know about a data type. People are
permitted to read the documentation and even search the internet.
> I suggest to make a way for this usage. Maybe NotImplementedType can
> accept *args, and NotImplemented can be callable, equal to __init__:
What would the result of calling NotImplemented be?
If it is the immutable NotImplemented singleton then supplying any
arguments would be a no-op. They would just be ignored.
If it returns something else, then it wouldn't be the NotImplemented
singleton and that would become the operator's result.
If we made NotImplemented mutable, that would lead to difficulty with
multi-threaded code. One thread could modify the object, changing the
error message, before another thread made use of that message. Fixing
that would require locks, which would have a big performance impact. I
would expect that it would slow down almost every operator.
If we changed NotImplemented to no longer be a singleton, that would
break code that checks for it with the `is` operator, which is one of
the two main uses for `is` (the other is checking for None).
Making this work would be a big change for a very small benefit.
*If* we thought that being able to customize TypeErrors was important,
it would, I think, be easier to add a new protocol to operators. After
going through the whole left-and-right operand dance and calling the
appropriate methods, if neither operand supported the operator, then the
interpreter could look at each operand in turn for a new dunder, and
then call that to get the customized error message.
The API for that dunder would be complicated, but here is my quick
design. There are two cases, for unary functions and operators and for
binary operators.
The unary operator case: function or operator which calls `__OP__` would
then look for a new dunder `__OP_error__` containing the error message.
So:
complex.__float_error__ = 'use abs(z) instead'
The binary operator case: the operator which calls `__OP__` would then
look for a new *callable* dunder that returns an error message.
For example, matrices don't define division, so we could do:
class Matrix:
def __true_division_error__(self, type_of_other):
if type_of_other is Matrix:
# Matrix / Matrix not permitted
return "matrix division not defined; try multiplying by the
inverse matrix"
If the `__OP_error__` dunder returns None or NotImplemented, or doesn't
exist, no additional message is appended to the TypeError.
This is pretty complicated, for not a lot of benefit IMO. I think people
should just learn to read the docs.
--
Steve
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/python-ideas@python.org/message/ECC3NPAPC43GYDA46PELOL3UGRNWAYNW/
Code of Conduct: http://python.org/psf/codeofconduct/