在现代Python中声明自定义异常类的正确方法是什么?我的主要目标是遵循其他异常类所具有的任何标准,以便(例如)由捕获异常的任何工具打印出异常中包含的任何额外字符串。

所谓"现代Python",我指的是在Python 2.5中运行但在Python 2.6和Python 3中"正确"的东西。做事的方法。我所说的"自定义"是指一个异常对象,它可以包含关于错误原因的额外数据:一个字符串,也可能是一些与异常相关的其他任意对象。

我在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,但是我从来不知道如何使用它。我也不确定这是向前发展的正确方式;我在网上找到的很多讨论都表明,他们正试图在python3中取消args。

更新:有两个答案建议重写__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

这样,您就可以将dict的错误消息传递给第二个参数,然后使用e.errors进行处理

Python 3更新:在python3 +中,您可以使用稍微紧凑一点的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

但是,这样定义的异常是不可选的;点击这里查看讨论:stackoverflow.com/questions/16244923/…

@jiakai意味着"可pickle"。:-)

对于现代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

[collapse title=""]

  • "但这将在未来被弃用"——这仍然是为了弃用吗?Python 3.7似乎仍然乐于接受Exception(foo, bar, qux)。
  • 自从上次尝试由于转换的痛苦而失败后,它还没有看到任何最近的工作来破坏它,但是这种用法仍然不受欢迎。我将更新我的答案来反映这一点。
  • @frnknstn,为什么不鼓励这样做?对我来说,这是个不错的习语。
  • 首先,使用元组存储异常信息与使用字典存储异常信息相比没有什么好处。如果您对异常更改背后的原因感兴趣,请查看PEP352

[/collapse]

[wp_ad_camp_1]


"Proper way to declare custom exceptions in modern Python?"

这很好,除非你的异常是一种更特殊的异常:

[cc lang="python"]class MyException(Exception):

pass

或者更好(也许是完美的),而不是pass给出一个docstring:

class MyException(Exception):

"""Raise for my specific kind of exception"""

<

子类化异常子类/ hh2 >

从文档

Exception

All built-in, non-system-exiting exceptions are derived from this class.

All user-defined exceptions should also be derived from this

class.

这意味着,如果您的异常是一种更具体的异常类型,则子类化该异常而不是通用的Exception(结果将是您仍然按照文档的建议从Exception派生)。此外,您至少可以提供一个docstring(而不必强制使用pass关键字):

class MyAppValueError(ValueError):

'''Raise when my specific value is wrong'''

设置使用自定义__init__创建的属性。避免将dict作为位置参数传递,代码的未来用户将会感谢您。如果您使用了deprecated message属性,那么您自己分配它将避免使用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__。内置组件非常好,您的合作继承确保您使用它。顶部答案的评论

Maybe I missed the question, but why not:

class MyException(Exception):

pass

同样,上面的问题是,为了捕获它,您要么必须指定它的名称(如果在其他地方创建,则需要导入它),要么捕获异常(但是您可能不准备处理所有类型的异常,您应该只捕获准备处理的异常)。类似的批评如下,但除此之外,这不是通过super初始化的方法,如果你访问message属性,你会得到一个DeprecationWarning:

Edit: to override something (or pass extra args), do this:

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

That way you could pass dict of error messages to the second param, and get to it later with e.errors

它还需要传入两个参数(除了self)。不多不少。这是一个有趣的约束,未来的用户可能不会喜欢。

直接地说,它违反了Liskov可替换性。

我将演示这两个错误:

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

Traceback (most recent call last):

File"", line 1, in

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'

你好从2018年!BaseException.message在Python 3中没有了,所以这个评论只适用于旧版本,对吗?

关于Liskov可替代性的批评仍然有效。第一个参数作为"消息"的语义也存在争议,但我不认为我要讨论这一点。当我有更多的空闲时间时,我会多看看这个。

FWIW,对于python3(至少对于3.6+),我们将重新定义MyAppValueError的__str__方法,而不是依赖于message属性

为什么要避免将dict作为位置参数传递?它保留了所有的原始语义,包括(__repr__/__str__),用户可以通过.args[0]根据frnknstn的答案解析dict吗?(您在文档字符串中注意到了这一点,不是吗?)

@AaronHall,你能详细说明一下子类化ValueError而不是Exception的好处吗?您声明这就是文档的含义,但是直接阅读并不支持这种解释,在Python教程中,在用户定义异常下,它明确地让用户选择:"异常通常应该直接或间接地从Exception类派生。"因此,我很想知道你的观点是否合理。

@ostergaard现在不能完全回答,但是简而言之,用户可以获得额外的选项来捕获ValueError。如果它在值错误的类别中,这是有意义的。如果它不属于值错误的范畴,我将在语义上反对它。对于程序员来说,还有一些细微差别和推理的空间,但如果适用,我更喜欢具体化。我很快会更新我的答案,以便更好地解决这个问题。

@AaronHall谢谢,这很有道理,我同意。尽管我认为把这一意义归于文档是一种延伸。

see how exceptions work by default if one vs more attributes are used (tracebacks omitted):

>>> 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__方法,而不是使用message,构造异常时提供的args将位于异常对象的args属性中。

不,"消息"不是禁止的。它只是弃用。您的应用程序可以很好地使用消息。当然,您可能希望消除弃用错误。

当您为您的应用程序创建自定义异常类时,它们中的许多并不仅仅来自Exception,而是来自其他异常,如ValueError或类似的异常。然后你必须适应他们对变量的使用。

如果您的应用程序中有很多异常,通常最好为所有异常都提供一个通用的自定义基类,这样模块的用户就可以这样做

try:

...

except NelsonsExceptions:

...

在这种情况下,您可以执行所需的__init__ and __str__,因此不必对每个异常都重复它。但是简单地调用message变量而不是message就可以了。

在任何情况下,您只需要在执行与Exception本身不同的操作时使用__init__ or __str__。因为如果不赞成,你需要两者,否则你会得到一个错误。每个类需要的额外代码并不多。,)

从Python 3.8 (2018, https://docs.python.org/dev/whatsnew/3.8.html)开始,推荐的方法仍然是:

class CustomExceptionName(Exception):

"""Exception raised when very uncommon things happen"""

pass

请不要忘记记录,为什么需要自定义异常!

如果你需要,这是处理异常的方法与更多的数据:

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(self.payload)) # Detail: Forgot upgrading from Python 1

payload=None使其可酸洗是很重要的。在丢弃它之前,您必须调用error.__reduce()__。加载将按预期工作。

如果需要将大量数据传输到某个外部结构,您可能应该研究如何使用pythons return语句找到解决方案。这对我来说似乎更清楚/更像蟒蛇。高级异常在Java中大量使用,当使用框架并必须捕获所有可能的错误时,这有时会很烦人。

嗯,Python 3。8中有什么变化?出于好奇,我浏览了你发布的链接,但是没有提到任何与这个主题相关的内容……

如果什么都没有改变,就不需要一个新的答案;对公认的答案做一个简单的评论就足够了。

至少,当前的文档表明这是一种方法(至少没有使用__str__),而不是使用super().__init__(...)的其他答案。只是遗憾的是,仅仅为了更好的"默认"序列化,覆盖__str__和__repr__可能是必要的。

试试这个例子

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")

python中自定义错误_在现代Python中声明自定义异常的正确方法?相关推荐

  1. eclipse中自定义视图_如何在Windows中自定义文件夹视图设置

    eclipse中自定义视图 While the Windows File Explorer seems somewhat simplified compared to older versions, ...

  2. python打开方式错误_浅谈python 调用open()打开文件时路径出错的原因

    昨晚搞鼓了一下python的open()打开文件 代码如下 def main(): infile =open("C:\Users\Spirit\Desktop\bc.txt",'r ...

  3. python编写自定义函数计算一维numpy数组中与指定目标数值最接近(距离最近)的数值(find closest value in numpy array to a certain value)

    python编写自定义函数计算一维numpy数组中与指定目标数值最接近(距离最近)的数值(find closest value in numpy array to a certain value) 目 ...

  4. php输出mysql错误日志_PHP_PHP中把错误日志保存在系统日志中(Windows系统),【将错误记录到系统日志中】 - phpStudy...

    PHP中把错误日志保存在系统日志中(Windows系统) [将错误记录到系统日志中] 在 php.ini 中将 error_log 设置为: error_log = syslog 或者在运行时使用 i ...

  5. php 系统日志,PHP中把错误日志保存在系统日志中(Windows系统)

    PHP中把错误日志保存在系统日志中(Windows系统) [将错误记录到系统日志中] 在 php.ini 中将 error_log 设置为: 复制代码 代码如下: error_log = syslog ...

  6. php 保存错误日志,PHP中把错误日志保存在系统日志中_PHP教程

    PHP中把错误日志保存在系统日志中 这篇文章主要介绍了PHP中把错误日志保存在系统日志中(Windows系统),本文讲解了设置方法和查看方法,需要的朋友可以参考下 [将错误记录到系统日志中] 在 ph ...

  7. python中自定义错误_Python中的自定义错误消息

    所以我在练习单元测试,我有一个关于错误消息的问题.我正在尝试创建一个自定义错误消息,当测试失败时将显示该消息.这是一个基本的Hello World程序.测试运行得很好,但下面是我得到的错误消息.在F ...

  8. python词云自定义形状_如何在Python中生成任何形状的词云

    作者 | Julia Kho 编辑| 代码医生团队 在本文中,我们将探讨如何在python中以您想要的任何形状生成文字云.我们将通过一个示例来说明如何在房屋的自定义形状中创建简单的文字云,如上图所示. ...

  9. python一直报缩进错误_如何避免Python中的缩进错误

    Python是当今编程界领先和新兴的编程平台之一.凭借其丰富的功能和巨大的灵活性,人们可以在这个平台上实现很多,只要他们知道如何操作它.在Python中的这个缩进错误中,我们将介 Python是当今编 ...

最新文章

  1. Android ORMLite 框架的入门用法
  2. java工程中的.classpathaaaaaaaaaaaaaaaa转载
  3. Maven的构建配置文件(Build Profiles)
  4. android 返回图标,在Toolbar中添加一个返回图标
  5. jquery插件编写
  6. 浅析神经网络为什么能够无限逼近任意连续函数
  7. C#实现整数冒泡排序、选择排序
  8. mysql 字段 as_mysql 字段as详解及实例代码
  9. HDU2569 彼岸【打表+记忆化递归】
  10. Hyperledger fabric v2.3 通道channel 翻译
  11. selenium之chrome driver版本选择
  12. python编写dll文件_.dll 文件编写和使用
  13. 【Python】列表解析式
  14. 谢特——后缀数组+tire 树
  15. MapServer 7.0.3 Documentation 翻译
  16. MySQL添加索引及添加字段并建立索引
  17. 互联网,因特网和万维网的区别是什么?
  18. mysql表disable_[MySQL优化案例]系列 -- DISABLE/ENABLE KEYS的作用
  19. 高数第一章思维导图(目前待录取,原件在评论区分享)
  20. 陌上红尘,只影向谁依

热门文章

  1. 动态扩展硬盘,固定尺寸硬盘,差异硬盘
  2. oracle:多重子查询的实战应用
  3. 北航计算机学院国家奖学金,Hua Guo
  4. 爱普生Epson WF-6093 打印机驱动
  5. WMS系统与ERP仓储管理的差异
  6. 【ARMv8 编程】A64 数据处理指令——位域字节操作指令
  7. 计算机网络——4.入门思科网络设备
  8. linux如何彻底的删除文件
  9. Spring Boot教程(十三):Spring Boot文件上传
  10. gitlab 项目加人