【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
在现代Python中声明自定义异常类的正确方法是什么? 我的主要目标是遵循其他异常类具有的任何标准,以便(例如)我捕获到异常中的任何工具都会打印出我包含在异常中的任何多余字符串。
“现代Python”是指可以在Python 2.5中运行但对于Python 2.6和Python 3. *是“正确”的方式。 所谓“自定义”,是指一个Exception对象,该对象可以包含有关错误原因的其他数据:字符串,也许还包括与该异常相关的其他任意对象。
我在Python 2.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
,但是我从来不知道如何使用它。 我也不确定这是前进的正确方法。 我在网上发现的很多讨论都表明他们正在尝试消除Python 3中的args。
更新:有两个答案建议覆盖__init__
和__str__
/ __unicode__
/ __repr__
。 好像要打很多笔,有必要吗?
#1楼
使用现代的Python异常,您不需要滥用.message
,也不必覆盖.__str__()
或.__repr__()
或任何它。 如果在引发异常时,您所希望的只是一条提示性消息,请执行以下操作:
class MyException(Exception):
pass
raise MyException("My hovercraft is full of eels")
这将以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
#2楼
您应该重写__repr__
或__unicode__
方法而不是使用message,构造异常时提供的args
将位于异常对象的args
属性中。
#3楼
也许我错过了这个问题,但是为什么不呢?
class MyException(Exception):
pass
编辑:要覆盖某些内容(或传递额外的args),请执行以下操作:
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
这样,您可以将错误消息的字典传递给第二个参数,并在以后使用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
#4楼
不,“消息”不是禁止的。 只是过时了。 您的应用程序可以正常使用消息。 但是,您当然可以摆脱折旧错误。
当为应用程序创建自定义Exception类时,它们中的许多不仅仅从Exception继承子类,还从ValueError之类的其他子类继承。 然后,您必须适应它们对变量的使用。
而且,如果您的应用程序中有很多异常,通常最好为所有异常都拥有一个通用的自定义基类,以便模块的用户可以
try:
...
except NelsonsExceptions:
...
在那种情况下,您可以在那里__init__ and __str__
所需的__init__ and __str__
,因此您不必为每个异常重复此操作。 但是简单地调用message变量而不是message可以解决问题。
无论如何,如果您做的事情与Exception本身不同,则只需要__init__ or __str__
。 并且因为如果不赞成使用,那么您将同时需要这两种方法,否则会出错。 每个类不需要很多额外的代码。 ;)
#5楼
见异常缺省情况下是如何工作的,如果一个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
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3141680