在 python 中引发自定义异常

Raising custom Exception in python

提问人:inavis 提问时间:8/22/2023 最后编辑:egleaseinavis 更新时间:8/27/2023 访问量:227

问:

我是 python 异常处理的新手,正在试验我在下面编写的代码,并有很多疑问:

class CustomException(Exception):
    def __init__(self,msg):
        self.msg=msg
        print( 'custom exception occurred')

class Test:
    def __init__(self):
        self.func1()

    def func1(self):
        try:
            print(40/0)
        except Exception as e:
            print("entered exception block")
            raise CustomException("Error message")
obj=Test()

如果我注释掉行,程序通过在 except 块中打印“输入的异常块”来处理代码,并且不给出 Traceback 堆栈,但 为什么如果同时有 print 和 raise 语句获得以下输出:raise CustomException("Error message")

entered exception block
custom exception occurred
Traceback (most recent call last):
  File "c:\Users\inavis\Desktop\customException1.py", line 12, in func1
    print(40/0)
          ~~^~
ZeroDivisionError: division by zero

在处理上述异常的过程中,又发生了一次异常:

Traceback (most recent call last):
  File "c:\Users\inavis\Desktop\customException1.py", line 16, in <module>
    obj=Test()
        ^^^^^^
  File "c:\Users\inavis\Desktop\customException1.py", line 8, in __init__
    self.func1()
  File "c:\Users\inavis\Desktop\customException1.py", line 15, in func1
    raise CustomException("Error message")
CustomException: Error message

我得到存在自定义异常,因为我正在提出它,但为什么是 ZeroDivisionError?由于 print 和 raise 语句存在于此特定 except 块中,这是否意味着应该处理异常 ZeroDivisionError?

python-3.x 异常 引发

评论

0赞 DeepSpace 8/22/2023
退后一步,重新读取您收到的堆栈跟踪。首先发生 a,然后在块中处理,然后在处理过程中引发。这完全是预期的行为。ZeroDivisionErrorexceptCustomException
0赞 DeepSpace 8/22/2023
“这并不意味着应该处理异常 ZeroDivisionError”——它被处理了。这是处理的。CustomException
0赞 DeepSpace 8/22/2023
作为最后一条评论,这与用户定义的异常这一事实没有任何关系。CustomException
0赞 inavis 8/22/2023
谢谢,这是有道理的。只是一个小问题,因为我在 except 块中提出了 CustomException。处理方法是什么?

答:

0赞 tdelaney 8/22/2023 #1

这是设计使然。该语句有一个子句,允许您执行异常链接。如果您在异常处理程序中,则会自动完成此操作。从文档中 raise 语句raisefromraise

如果在以下情况下引发新异常,则类似的机制会隐式工作 已处理异常。可以处理异常 当使用 except 或 finally 子句或 with 语句时。这 然后,将上一个异常附加为新异常的上下文属性

由于您在块中,Python 会将上一个异常附加到新异常的属性,并且该上下文可能会显示给用户。它不是您可以捕获或需要处理的东西,尽管如果出于某种原因,代码可以处理异常链。raiseexception__context__

这可能很烦人,并且可能会阻止清理和删除原始异常中的对象。您可以通过显式链接来禁止自动链接None

class CustomException(Exception):
    def __init__(self,msg):
        self.msg=msg
        print( 'custom exception occurred')

class Test:
    def __init__(self):
        self.func1()

    def func1(self):
        try:
            print(40/0)
        except Exception as e:
            print("entered exception block")
            raise CustomException("Error message") from None
obj=Test()

输出

entered exception block
custom exception occurred
Traceback (most recent call last):
  File "/home/td/tmp/e/o.py", line 16, in <module>
    obj=Test()
  File "/home/td/tmp/e/o.py", line 8, in __init__
    self.func1()
  File "/home/td/tmp/e/o.py", line 15, in func1
    raise CustomException("Error message") from None
__main__.CustomException: Error message

Python 不会自动重新引发异常。如果您的代码知道如何处理错误,它可以采取适当的操作,并且代码将在 try/except/finally 子句之后恢复(如果代码存在,则运行代码)。finally

而且您不需要捕获所有异常。在您的示例中,可以跳过 try/除非它没有任何有用的事情可做。例外会去 的来电者等等......直到程序的顶部。如果没有人抓住它,程序就会终止。func1func1

示例代码的目的是将异常转换为在域中更有意义的异常。这很常见。与其期望调用方找出像 ValueError 这样模糊的东西,不如将其转换为问题域中的某些内容。

评论

0赞 inavis 8/22/2023
谢谢你的回答!我能知道,我们是否必须处理 except 块中引发的异常,如果是这样,如何处理?还是为了停止程序而编写的?为什么我们需要在 except 块中引发异常?
0赞 tdelaney 8/22/2023
@inavis - 我添加了一些文字,希望能回答你的问题。