45

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!

5 Answers 5

59

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
Sign up to request clarification or add additional context in comments.

3 Comments

I think that this is actually the best answer.
This works great and looks elegant. However, I would like to note that pylint isn't too happy with this and calls it useless super delegation.
Also pylint reports about keyword-arg-before-vararg
30

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.

Comments

12

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.

Comments

1

Just going to throw out this solution. This will allow you to define a message with the class definition.

First a base exception class:

class DefaultException(Exception):
    """A class to define a default message with the exception definition"""
    MSG = ''

    def __init__(self, *args, message=None, **kwargs):
        if message is None:
            message = self.MSG
        
        super().__init__(message)

Now we can define exceptions with their default messages easily:

class CustomException(DefaultException):
    """This is just an example exception"""
    MSG = 'This is a default message!'

You can even modify the DefaultException to format the default message using the kwargs, if you want there to be some formatting as well

Comments

0

The messages can even be dynamic. I use this to tweak some error messages in my project. Works like a charm.

class PinNotFoundError(BaseException):
    """ Error class to thrown, when a pin cannot be found """
    def __init__(self, pin, *args, **kwargs):
        msg = f'Pin {pin} cannot be resolved to a pin on the device.'
        super().__init__(msg, *args, **kwargs)


Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.