[Python-ideas] Arguments to exceptions
Ken Kundert
python-ideas at shalmirane.com
Mon Jul 3 04:59:02 EDT 2017
I think in trying to illustrate the existing behavior I made things more
confusing than they needed to be. Let me try again.
Consider this code.
>>> import Food
>>> try:
... import meals
... except NameError as e:
... name = str(e).split("'")[1] # <-- fragile code
... from difflib import get_close_matches
... candidates = ', '.join(get_close_matches(name, Food.foods, 1, 0.6))
... print(f'{name}: not found. Did you mean {candidates}?')
In this case *meals* instantiates a collection of foods. It is a Python file,
but it is also a data file (in this case the user knows Python, so Python is
a convenient data format). In that file thousands of foods may be instantiated.
If the user misspells a food, I would like to present the available
alternatives. To do so, I need the misspelled name. The only way I can get it
is by parsing the error message.
That is the problem. To write the error handler, I need the misspelled name.
The only way to get it is to extract it from the error message. The need to
unpack information that was just packed suggests that the packing was done too
early. That is my point.
Fundamentally, pulling the name out of an error message is a really bad coding
practice because it is fragile. The code will likely break if the formatting or
the wording of the message changes. But given the way the exception was
implemented, I am forced to choose between two unpleasant choices: pulling the
name from the error message or not giving the enhanced message at all.
The above is an example. It is a bit contrived. I simply wanted to illustrate
the basic issue in a few lines of code. However, my intent was also to
illustrate what I see as a basic philosophical problem in the way we approach
exceptions in Python:
It is a nice convenience that an error message is provided by the source of
the error, but it should not have the final say on the matter.
Fundamentally, the code that actually presents the error to the user is in
a better position to produce a message that is meaningful to the user. So,
when we raise exceptions, not only should we provide a convenient human
readable error message, we should anticipate that the exception handler may
need to reformat or reinterpret the exception and provide it with what it
need to do so.
The current approach taken by exceptions in Python makes that unnecessarily
difficult.
PEP 352 suggests that this situation can be handled with a custom exception, and
that is certainly true, but that only works if the person writing the code that
raises the exception anticipates the need for passing the components of the
error message as separate arguments. But as we can see from the NameError,
AttributeError, etc, they don't always do. And PEP 352 actively discourages them
from doing so.
What I am hoping to do with this proposal is to get the Python developer
community to see that:
1. The code that handles the exception benefits from having access to the
components of the error message. In the least it can present the message to
the user is the best possible way. Perhaps that means enforcing a particular
style, or presenting it in the user's native language, or perhaps it means
providing additional related information as in the example above.
2. The current approach to exceptions follows the opposite philosophy,
suggesting that the best place to construct the error message is at the
source of the error. It inadvertently puts obstacles in place that make it
difficult to customize the message in the handler.
3. Changing the approach in the BaseException class to provide the best of both
approaches provides considerable value and is both trivial and backward
compatible.
-Ken
More information about the Python-ideas
mailing list