适当的方式声明的定义的例外在现代蟒蛇?
-
19-09-2019 - |
题
什么是适当的方式声明的定义的异常类在现代蟒蛇?我的主要目标是按照任何标准的其他例外类,所以(例如)任何额外的串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__
只有一个论点。 - 当建立一个图书馆,定义的基类继承的例外。
- 提供详细信息的错误。
- 继承自内的例外情况类型时,它才有意义。
还有的信息在组织(模块)和包装的例外情况,我建议来阅读指南。