Default message in custom exception – Python

Question:

I want to create a custom exception in Python, that when raised without any arguments, it will print a default message.

Code Example:

class CustomException(Exception):
    pass # some code

raise CustomException()

and get the below output:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.CustomException: This is a default message!
Asked By: pgmank

||

Answers:

The solution is given by the bellow code:

class CustomException(Exception):
    def __init__(self, *args, **kwargs):
        default_message = 'This is a default message!'

        # if any arguments are passed...
        # If you inherit from the exception that takes message as a keyword
        # maybe you will need to check kwargs here
        if args:
            # ... pass them to the super constructor
            super().__init__(*args, **kwargs)
        else: # else, the exception was raised without arguments ...
                 # ... pass the default message to the super constructor
                 super().__init__(default_message, **kwargs)

An equivalent but more succinct solution is:

class CustomException(Exception):
    def __init__(self, *args, **kwargs):
        default_message = 'This is a default message!'

        # if no arguments are passed set the first positional argument
        # to be the default message. To do that, we have to replace the
        # 'args' tuple with another one, that will only contain the message.
        # (we cannot do an assignment since tuples are immutable)
        # If you inherit from the exception that takes message as a keyword
        # maybe you will need to check kwargs here
        if not args: args = (default_message,)

        # Call super constructor
        super().__init__(*args, **kwargs)

An even more succinct but restricted solution, in a way that you can only raise the CustomException with no arguments is:

class CustomException(Exception):
     def __init__(self):
         default_message = 'This is a default message!'
         super().__init__(default_message)

You can of course save one line, in each of the above solutions, if you just pass the string literal to the constructor rather than using the default_message variable.

If you want the code to be Python 2.7 compatible, then you just replace the: super() with super(CustomException, self).

Now running:

>>> raise CustomException

will output:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.CustomException: This is a default message!

and running:

raise CustomException('This is a custom message!')

will output:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.CustomException: This is a custom message!

This is the output that the first 2 solutions’ code will produce. The last solution, differs in that calling it with at least one argument, like:

raise CustomException('This is a custom message!')

it will output:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes 1 positional argument but 2 were given

because it does not permit any arguments to be passed to the CustomException when it is raised.

Answered By: pgmank

This is the simplest solution IMHO how to define custom exception with a default message that can be overridden if needed:

class CustomException(Exception):
    def __init__(self, msg='My default message', *args, **kwargs):
        super().__init__(msg, *args, **kwargs)

Usage example:

In [10]: raise CustomException
---------------------------------------------------------------------------
CustomException                           Traceback (most recent call last)
<ipython-input-10-259ae5202c8e> in <module>
----> 1 raise CustomException

CustomException: My default message

In [11]: raise CustomException()
---------------------------------------------------------------------------
CustomException                           Traceback (most recent call last)
<ipython-input-11-c1921a8781a6> in <module>
----> 1 raise CustomException()

CustomException: My default message

In [12]: raise CustomException('Foo bar')
---------------------------------------------------------------------------
CustomException                           Traceback (most recent call last)
<ipython-input-12-7efbf94f7432> in <module>
----> 1 raise CustomException('Foo bar')

CustomException: Foo bar
Answered By: illagrenan

As regarded in an answer to this question, this is a pretty good way to declare a custom exception:

class MyException(Exception):
    """Docstring here"""

If one has many exceptions to define, one may use a subclass of Exception as their exceptions’ superclass to make these exceptions’ docstrings their default messages:

class DocDefaultException(Exception):
    """Subclass exceptions use docstring as default message"""
    def __init__(self, msg=None, *args, **kwargs):
        super().__init__(msg or self.__doc__, *args, **kwargs)

class MyException(DocDefaultException):
    """Docstring here."""

raise MyException

Output:

Traceback (most recent call last):
  File "C:************************.py", line 9, in <module>
    raise MyException
__main__.MyException: Docstring here

A decorator also works to use the docstring of a custom exception as its default message:

import functools

def docstring_message(cls):
    """Decorates an exception to make its docstring its default message."""
    # Must use cls_init name, not cls.__init__ itself, in closure to avoid recursion
    cls_init = cls.__init__ 
    @functools.wraps(cls.__init__)
    def wrapped_init(self, msg=cls.__doc__, *args, **kwargs):
        cls_init(self, msg, *args, **kwargs)
    cls.__init__ = wrapped_init
    return cls

@docstring_message
class MyException(Exception):
    """Docstring here"""

raise MyException

Output:

Traceback (most recent call last):
  File "C:************************.py", line 16, in <module>
    raise MyException
__main__.MyException: Docstring here

Of course, one should raise exceptions with a descriptive message, but a default fallback is sufficient sometimes and a docstring can suffice if written correctly.

Answered By: Ryan Laursen
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.