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

pgm*_*ank 9 python exception

我想在Python中创建一个自定义异常,当没有任何参数引发时,它将打印一个默认消息.

案例:

>>> class CustomException(Exception):
       # some code here

>>> raise CustomException
Run Code Online (Sandbox Code Playgroud)

并获得以下输出:

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

ill*_*nan 34

这是最简单的解决方案恕我直言如何使用默认消息定义自定义异常,如果需要,可以覆盖该消息:

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

用法示例:

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
Run Code Online (Sandbox Code Playgroud)

  • pylint 还报告了有关 keywords-arg-before-vararg 的信息 (3认同)
  • 这效果很好而且看起来很优雅。然而,我想指出 pylint 对此并不太满意,并称其为无用的超级委托。 (2认同)

pgm*_*ank 11

解决方案由以下代码给出:

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

        # if any arguments are passed...
        if args or kwargs:
            # ... 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)
Run Code Online (Sandbox Code Playgroud)

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

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 not (args or kwargs): args = (default_message,)

         # Call super constructor
         super().__init__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

一个更简洁但受限制的解决方案,只能在不带参数的情况下引发CustomException:

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

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

如果您希望代码与Python 2.7兼容,那么您只需替换:super()with super(CustomException, self).

现在运行:

>>> raise CustomException
Run Code Online (Sandbox Code Playgroud)

将输出:

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

和运行:

raise CustomException('This is a custom message!')
Run Code Online (Sandbox Code Playgroud)

将输出:

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

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

raise CustomException('This is a custom message!')
Run Code Online (Sandbox Code Playgroud)

它将输出:

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

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


Rya*_*sen 11

正如对这个问题的回答中所考虑的,这是声明自定义异常的一个很好的方法:

class MyException(Exception):
    """Docstring here"""
Run Code Online (Sandbox Code Playgroud)

如果要定义许多异常,则可以使用 的子类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
Run Code Online (Sandbox Code Playgroud)

输出:

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

装饰器还可以使用自定义异常的文档字符串作为其默认消息:

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
Run Code Online (Sandbox Code Playgroud)

输出:

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

当然,应该使用描述性消息引发异常,但有时默认后备就足够了,如果编写正确,文档字符串就足够了。