Reputation: 5819
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!
Upvotes: 45
Views: 28834
Reputation: 81
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
Upvotes: 1
Reputation:
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)
Upvotes: 0
Reputation: 647
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.
Upvotes: 12
Reputation: 5819
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.
Upvotes: 30
Reputation: 6555
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
Upvotes: 59