raise from
syntax, but the basic story remains the same with Python 2.7. *This time, I would like to talk about using an instance of a Python exception class directly as an argument of the exception class, but in the first place
I'm not sure about the situation "** Make an instance of the exception class directly as an argument of the exception class **".
I'm sure there are people who say that, so let's set a little more specific situation.
First, let's say you created a spam module in Python, prepared SpamError
as the base class for module exceptions, and created a custom exception classSpamIndexError
that inherited SpamError
and the Python standard ʻIndexError`.
It looks like this when you actually write it.
spam.py
class SpamError(Exception):
pass
class SpamIndexError(SpamError, IndexError):
pass
Next, because of the requirement that users who use the spam module can catch Python standard errors that occur in the spam module with ʻexcept spam.SpamError as exception:` etc., in the spam module
spam.py
try:
[][0] #Index Error occurs
except IndexError as original:
raise SpamIndexError(original) from original
I decided to write code like this.
The reason that the argument of SpamError
in the last line is ʻoriginal, which is an exception supplemented by the except statement, is intended to display a message equivalent to the original ʻIndexError
.
This is a common practice in many sources.
When I run the above code,
python
Traceback (most recent call last):
File "./spam.py", line 16, in <module>
[][0] #Index Error occurs
IndexError: list index out of range
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "./spam.py", line 18, in <module>
raise SpamIndexError(original) from original
spam.SpamIndexError: list index out of range
Is displayed.
Both ʻIndexError and
SpamIndexErrorare displayed as
list index out of range`.
There is no problem so far.
But unfortunately if this was a KeyError
instead of a ʻIndexError`
python
Traceback (most recent call last):
File "./spam.py", line 16, in <module>
{}[0] #KeyError occurs
KeyError: 0
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "./spam.py", line 18, in <module>
raise SpamKeyError(original) from original
spam.SpamKeyError: KeyError(0,)
Will be displayed like this.
The original KeyError
is displayed as KeyError: 0
, but the SpamKeyError
is displayed asspam.SpamKeyError: KeyError (0,)
.
ʻIndexError evaluates the argument with
str () , but
KeyErrorevaluates with
repr ()` if there is one argument, so this is the case.
To avoid this
python
raise SpamKeyError(original) from original
Line,
python
raise SpamKeyError(*original.args) from original
And instead of ʻoriginal, take the argument of the original exception,
* original.args`.
Then
python
Traceback (most recent call last):
File "./spam.py", line 16, in <module>
{}[0] #KeyError occurs
KeyError: 0
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "./spam.py", line 18, in <module>
raise SpamKeyError(*original.args) from original
spam.SpamKeyError: 0
Is displayed, and SpamKeyError
is displayed in the same way as the original KeyError
.
However, it's okay to take * original.args
as an argument only if the exception you raise inherits from the class of the original exception.
If not,
python
raise SpamError(str(original)) from original
It is safe to enclose the supplemented exception with str ()
and forcibly take a string as an argument.
If you want to raise an exception class that simply inherits from the ʻException` class,
python
raise SpamError(original) from original
It's okay to say that you don't have to enclose it in str ()
like, but in that case, the exception that was displayed as KeyError: 0
is displayed as spam.SpamError: 0
. Therefore, it becomes difficult to understand what kind of error it is from the message.
In any case, it would be a bad idea to just use the exception class instance ʻoriginal` as an argument.
Recommended Posts