Don't take an instance of a Python exception class directly as an argument to the exception class!

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 aslist 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 withrepr ()` 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

Don't take an instance of a Python exception class directly as an argument to the exception class!
Script to change the description of fasta
Script to tweet with multiples of 3 and numbers with 3 !!
Create an AWS GPU instance to train StyleNet
Usage to call a method of an instance before it is returned by __new__
Don't take an instance of a Python exception class directly as an argument to the exception class!
How to create an instance of a particular class from dict using __new__ () in python
Create an instance of a predefined class from a string in Python
Format when passing a long string as an argument of python
I want to clear up the question of the "__init__" method and the "self" argument of a Python class.
Hit a method of a class instance with the Python Bottle Web API
Python: Prepare a serializer for the class instance:
[Fabric] I was addicted to using boolean as an argument, so make a note of the countermeasures.
A python implementation of the Bayesian linear regression class
Why is the first argument of [Python] Class self?
Note: The meaning of specifying only * (asterisk) as an argument in the Python function definition.
Take a look at the Python built-in exception tree structure
[OCI] Python script to get the IP address of a compute instance in Cloud Shell
How to write a Python class
How to determine the existence of a selenium element in Python
Save the result of the life game as a gif with python
[Road to Python Intermediate] Call a class instance like a function with __call__
How to know the internal structure of an object in Python
A story that struggled to handle the Python package of PocketSphinx
How to check the memory size of a variable in Python
Calculate the editing distance as an index of pronunciation similarity [python]
How to check the memory size of a dictionary in Python
[Python3] Define a decorator to measure the execution time of a function
A story about a person who uses Python addicted to the judgment of an empty JavaScript dictionary
Take a look at the built-in exception tree structure in Python 3.8.2
[python] A note that started to understand the behavior of matplotlib.pyplot
I thought a Python class variable was an instance variable and died
[Python] A simple function to find the center coordinates of a circle
[Python] A program that rotates the contents of the list to the left
Have Alexa run Python to give you a sense of the future
[Python] A program that calculates the number of socks to be paired
Python Note: When you want to know the attributes of an object
[Introduction to Python] How to sort the contents of a list efficiently with list sort
I want to explain the abstract class (ABCmeta) of Python in detail.
I want to color a part of an Excel string in Python
The eval () function that calculates a string as an expression in python
Python code to determine the monthly signal of a relative strength investment
Get a datetime instance at any time of the day in Python
I made a program to check the size of a file in Python
Python: I want to measure the processing time of a function neatly
An example of the answer to the reference question of the study session. In python.
I made a function to see the movement of a two-dimensional array (Python)
[Python] How to make a class iterable
The story of making Python an exe
[python] Get a list of instance variables
[python] [meta] Is the type of python a type?
The story of blackjack A processing (python)
<Python> A quiz to batch convert file names separated by a specific character string as part of the file name
Do not specify a mutable object (list type, dictionary type, etc.) as the initial value of the function argument of python.
[Python] How to deal with the is instance error "is instance () arg 2 must be a type or tuple of types"
Various ways to read the last line of a csv file in Python
Python> function> Example of taking function as an argument> map (lambda x: 2 ** x, [1, 2, 3]) / locals () ['myprint'] (3.1415, 2.718)
[Circuit x Python] How to find the transfer function of a circuit using Lcapy
You can call the method of the class directly in Python3 without adding @staticmethod
[Python] Created a class to play sin waves in the background with pyaudio
[python] How to sort by the Nth Mth element of a multidimensional array
I made an appdo command to execute a command in the context of the app
Save an array of numpy to a wav file using the wave module
Build a python environment to learn the theory and implementation of deep learning
Python script to get a list of input examples for the AtCoder contest