自定义异常中的默认消息 - Python

41

我想在Python中创建一个自定义异常,当没有任何参数抛出时,它会打印出默认消息。

代码示例:

class CustomException(Exception):
    pass # some code

raise CustomException()

并获得以下输出:

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

52

这是我个人认为最简单的解决方案,用于定义带有默认消息的自定义异常,如果需要可以覆盖:

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

使用示例:

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

1
我认为这实际上是最好的答案。 - Gus
2
这个很好用,看起来也很优雅。然而,我想指出的是,pylint 对此并不太满意,并称其为无用的超级委托。 - Nuclear03020704
3
还有Pylint报告关于keyword-arg-before-vararg的问题。 - Nick Veld

29

解决方案如下所示:

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)

一个等效但更简洁的解决方案是:

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)

更加简洁但限制较多的解决方案是,您只能使用无参数的方式触发CustomException:

以下是实现代码:

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

如果您只是将字符串文字传递给构造函数而不使用default_message变量,则可以在上述每个解决方案中节省一行。

如果您想使代码与Python 2.7兼容,则只需用super(CustomException, self)替换super()

现在运行:

>>> raise CustomException

将输出:

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

并运行:

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

将输出:

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

这是前两个解决方案的代码将产生的输出。最后一个解决方案不同之处在于,如果至少使用一个参数调用它,如:

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

它将输出:

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

因为它不允许在引发CustomException时传递任何参数。


10

在回答这个问题时,以下是一种声明自定义异常的相当不错的方式:

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

如果需要定义许多异常,可以使用Exception类的子类作为这些异常的超类,使得这些异常的文档字符串成为它们的默认信息:

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

输出:

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

一个装饰器也可以使用自定义异常的文档字符串作为其默认消息:
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

输出:

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

当然,应该用描述性的信息来引发异常,但有时默认的回退足够了,如果正确撰写docstring(文档字符串),那就足够了。

0
这些消息甚至可以是动态的。我用它来调整我的项目中的一些错误消息。效果非常好。
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)



0
只是想提出一个解决方案。这将允许您在类定义中定义一个消息。
首先是一个基本的异常类:
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)

现在我们可以轻松地定义带有默认消息的异常了。
class CustomException(DefaultException):
    """This is just an example exception"""
    MSG = 'This is a default message!'

你甚至可以修改DefaultException,使用kwargs来格式化默认消息,如果你也想要一些格式化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接