什么是适当的方式声明的定义的异常类在现代蟒蛇?我的主要目标是按照任何标准的其他例外类,所以(例如)任何额外的串I包括在例外是印刷出通过任何工具,引起了异常。

通过"现代蟒蛇",我的意思是什么,将运行在Python2.5但是'正确'的Python2.6和Python3.* 的方式做事。和通过"定义",我的意思是一个例外的对象,可以包括额外的数据的有关原因的错误:一串,也许还有其他一些任意的对象有关的例外。

我被绊倒了由下列嘲警告Python2.6.2:

>>> class MyError(Exception):
...     def __init__(self, message):
...         self.message = message
... 
>>> MyError("foo")
_sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6

它似乎疯狂, BaseException 具有特殊的意义属性命名 message.我收集 PEP-352 这一属性没有特别的意义在2.5他们试图反对,因此我猜测,名称(以及一个单独的)是现在被禁止的?唉。

我还模糊的认识, Exception 有一些魔术参数 args, 但我从来不知道如何使用它。我也不确定这是正确的方式做事情;很多讨论,我在网上找到的建议,他们试图做的args Python3.

更新:两个答复有人建议压倒一切的 __init__, , __str__/__unicode__/__repr__.这似乎是一个很大的打字,是必要的?

有帮助吗?

解决方案

也许我错过了问题,但为什么不:

class MyException(Exception):
    pass

修改可重写的东西(或通过额外的参数),这样做:

class ValidationError(Exception):
    def __init__(self, message, errors):

        # Call the base class constructor with the parameters it needs
        super(ValidationError, self).__init__(message)

        # Now for your custom code...
        self.errors = errors

这样,你可以传递错误信息的字典到第二PARAM,并获得其后来与e.errors


<强> Python 3的更新:在Python 3+,则可以使用此稍微更紧凑的使用super()的:

class ValidationError(Exception):
    def __init__(self, message, errors):

        # Call the base class constructor with the parameters it needs
        super().__init__(message)

        # Now for your custom code...
        self.errors = errors

其他提示

与现代Python例外情况外,你不需要的滥用 .message, 或复盖 .__str__().__repr__() 或者任何它。如果你想要的是一个内容丰富的信息时,你的异常升高,这样做:

class MyException(Exception):
    pass

raise MyException("My hovercraft is full of eels")

这将给予回溯结束 MyException: My hovercraft is full of eels.

如果你想要更大的灵活性的例外,可以通过一词典的说法:

raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})

然而,要获得在这些细节在一个 except 方框是更复杂一点。详细信息都储存在 args 属性,它是一个列表。你会需要这样做:

try:
    raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
except MyException as e:
    details = e.args[0]
    print(details["animal"])

它仍然是可以通过在多个项目的例外和访问它们通过多元组指标,但这是 高度气馁 (甚至打算用于当时对一段时间后)。如果你需要更多比一个单一的信息,并对上述方法不足以为你,然后你应该子类 Exception 作为描述 教程.

class MyError(Exception):
    def __init__(self, message, animal):
        self.message = message
        self.animal = animal
    def __str__(self):
        return self.message
  

“正确的方式在现代Python来声明自定义异常?”

这是好的,除非你的例外,实在是一种更具体的异常:

class MyException(Exception):
    pass

或者更好的(也许完美的),而不是pass的给文档字符串:

class MyException(Exception):
    """Raise for my specific kind of exception"""

子类的子类的异常

文档

  

Exception

     

所有内置,非系统出射异常派生自此类。   所有的用户定义的异常也应该源于此   类。

这意味着如果您的例外是一种更具体的异常,子类是例外,而不是一般的Exception(其结果将是你仍然Exception获得的文档推荐) 。另外,还可以至少提供一个文档字符串(和不会被迫使用pass关键字):

class MyAppValueError(ValueError):
    '''Raise when my specific value is wrong'''

套装属性自己创建一个自定义__init__。避免传递一个字典作为一个位置参数,你的代码的未来用户会感谢你的。如果您使用的过时信息属性,分配给它自己会避免DeprecationWarning

class MyAppValueError(ValueError):
    '''Raise when a specific subset of values in context of app is wrong'''
    def __init__(self, message, foo, *args):
        self.message = message # without this you may get DeprecationWarning
        # Special attribute you desire with your Error, 
        # perhaps the value that caused the error?:
        self.foo = foo         
        # allow users initialize misc. arguments as any other builtin Error
        super(MyAppValueError, self).__init__(message, foo, *args) 

有真的没有必要写自己的__str____repr__。内建的人都很好,和您的合作继承确保您使用它。

顶端答案的批判

  

也许我错过了问题,但为什么不:

class MyException(Exception):
    pass

再次与上面的问题是,为了抓住它,你要么必须命名为专门(如果其他地方创造的导入而言)或捕获异常,(但你可能不准备处理所有类型例外的,你应该只捕获异常,你是准备处理)。类似的批评在下面,但另外那不是通过super初始化方式,如果你访问该消息的属性,你会得到一个DeprecationWarning

  

编辑:重写的东西(或通过额外的参数),这样做:

class ValidationError(Exception):
    def __init__(self, message, errors):

        # Call the base class constructor with the parameters it needs
        super(ValidationError, self).__init__(message)

        # Now for your custom code...
        self.errors = errors
  

这样,你可以传递错误信息的字典到第二PARAM,并获得其后来与e.errors

它还需要正好两个参数在(从self一边。)被传递没有更多不会少。这是未来的用户可能不欣赏一个有趣的约束。

要是直接的。 - 它违反里氏可替代性

我将说明这两个错误:

>>> ValidationError('foo', 'bar', 'baz').message

Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    ValidationError('foo', 'bar', 'baz').message
TypeError: __init__() takes exactly 3 arguments (4 given)

>>> ValidationError('foo', 'bar').message
__main__:1: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
'foo'

相比于:

>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'

见异常默认是如何工作的,如果一个 VS 多个属性被使用(回溯忽略):

>>> raise Exception('bad thing happened')
Exception: bad thing happened

>>> raise Exception('bad thing happened', 'code is broken')
Exception: ('bad thing happened', 'code is broken')

所以你可能希望有一种“例外模板”工作作为例外本身,以兼容的方式:

>>> nastyerr = NastyError('bad thing happened')
>>> raise nastyerr
NastyError: bad thing happened

>>> raise nastyerr()
NastyError: bad thing happened

>>> raise nastyerr('code is broken')
NastyError: ('bad thing happened', 'code is broken')

此可以很容易地与此子类来完成

class ExceptionTemplate(Exception):
    def __call__(self, *args):
        return self.__class__(*(self.args + args))
# ...
class NastyError(ExceptionTemplate): pass

如果你不喜欢这样的默认元组样表示,只需添加__str__方法将ExceptionTemplate类,如:

    # ...
    def __str__(self):
        return ': '.join(self.args)

,你就会有

>>> raise nastyerr('code is broken')
NastyError: bad thing happened: code is broken

您应该重写__repr____unicode__方法而不是当构造该异常会在异常对象的属性args使用消息,则提供ARGS。

<强>对于Python 3.8的(2018, https://开头docs.python.org/dev/whatsnew/3.8.html ),推荐的方法是仍然:

class CustomExceptionName(Exception):
    """Exception raised when very uncommon things happen"""
    pass

请不要忘记记录,为什么一个自定义异常是neccessary!

如果你需要,这是去更多的数据异常的方式:

class CustomExceptionName(Exception):
    """Still an exception raised when uncommon things happen"""
    def __init__(self, message, payload=None):
        self.message = message
        self.payload = payload # you could add more args
    def __str__(self):
        return str(self.message) # __str__() obviously expects a string to be returned, so make sure not to send any other data types

和获取它们喜欢:

try:
    raise CustomExceptionName("Very bad mistake.", "Forgot upgrading from Python 1")
except CustomExceptionName as error:
    print(str(error)) # Very bad mistake
    print("Detail: {}".format(error.payload)) # Detail: Forgot upgrading from Python 1

payload=None重要的是要使其泡菜-能。为之倾倒之前,你必须调用error.__reduce__()。载荷将正常工作。

您也许应该使用蟒蛇return声明,如果你需要多少数据被转移到一些外部结构寻找解决办法调查。这似乎是更清晰/更Python给我。先进例外在Java中大量使用,这有时可能是恼人的,使用框架和具有捕捉所有可能的错误时。

没有,“消息”不禁止。这只是过时。你的应用程序将正常工作使用的消息。但是你可能想摆脱当然弃用错误的。

当你的应用程序中创建自定义的异常类,很多人不只是从Exception的子类,但是从其他的像ValueError异常或类似。然后,你必须适应他们的变量使用。

如果你在你的应用中有许多例外它通常是一个好主意,有他们所有的世俗的基类,让你的模块的用户可以执行

try:
    ...
except NelsonsExceptions:
    ...

而在这种情况下,你可以做需要的有__init__ and __str__,这样你就不必再重复它为每一个例外。但是,简单地调用消息变量的东西比其他的消息确实的伎俩。

在任何情况下,你只有当你做一些从自身做什么异常不同需要的__init__ or __str__。而且因为如果不赞成,你再需要两个,或者你会得到一个错误。这不是一大堆额外的代码,你每级需要。 ;)

尝试这个例子

class InvalidInputError(Exception):
    def __init__(self, msg):
        self.msg = msg
    def __str__(self):
        return repr(self.msg)

inp = int(input("Enter a number between 1 to 10:"))
try:
    if type(inp) != int or inp not in list(range(1,11)):
        raise InvalidInputError
except InvalidInputError:
    print("Invalid input entered")

看到一个很好的文章"明确的指导,蟒蛇的例外".基本原则是:

  • 总是继承(至少)例外。
  • 总是呼叫 BaseException.__init__ 只有一个论点。
  • 当建立一个图书馆,定义的基类继承的例外。
  • 提供详细信息的错误。
  • 继承自内的例外情况类型时,它才有意义。

还有的信息在组织(模块)和包装的例外情况,我建议来阅读指南。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top