Python的`except`能匹配整个错误链中的所有错误吗?

huangapple go评论64阅读模式
英文:

Can python `except` match against all errors in the chain?

问题

以下是翻译好的部分:

我有一个Python应用程序,它构建了一个具有多个 raise from 子句的长错误链。我想要定义一个特定的 except 块来捕捉可能深入链中发生的一个值。看起来 Python 的 except 只会检查链中的第一个错误。是否有一种类似于 Go 中的 errors.is 的标准方法来遍历这个链?

示例:

class CustomException1(Exception):
  pass

class CustomException2(Exception):
  pass

class CustomException3(Exception):
  pass

def func_1():
    try:
        raise Exception("test failure")
    except Exception:
        raise CustomException1()


def func_2():
    try:
        func_1()
    except Exception as e:
        raise CustomException2() from e


def func_3():
    try:
        func_2()
    except Exception as e:
        raise CustomException3() from e


def func_4():
    try:
        func_3()
    except CustomException1:
        print("为 CustomException1 执行特定操作")
        pass
    except Exception:
        print("通用异常处理程序")
        pass

func_4()

我运行了上面的代码,看到输出是 "通用异常处理程序"。我想要异常与 CustomException1 子句匹配。是否有一种标准方法来遍历这个链?

英文:

I have a python application which constructs a long error chain with multiple raise from clauses. I'm interested defining a specific except block to catch one of the values that may occur deep within the chain. It appears that python except only checks against the first error in the chain. Is there a standard way to traverse the chain similar to errors.is in go?

Example:

class CustomException1(Exception):
  pass

class CustomException2(Exception):
  pass

class CustomException3(Exception):
  pass

def func_1():
    try:
        raise Exception("test failure")
    except Exception:
        raise CustomException1()


def func_2():
    try:
        func_1()
    except Exception as e:
        raise CustomException2() from e


def func_3():
    try:
        func_2()
    except Exception as e:
        raise CustomException3() from e


def func_4():
    try:
        func_3()
    except CustomException1:
        print("do something specific for CustomException1")
        pass
    except Exception:
        print("general exception handler")
        pass

func_4()

I ran the above code and saw the output "general exception handler". I'd like the exception to be matched by CustomException1 clause. Is there a standard method for traversing the chain?

答案1

得分: 2

从Python 3.11开始,您可以使用异常组来将多个异常打包成一个具有任意结构的单个包。在这里,我们仍然保留了调用堆栈所暗示的线性结构,但我们不需要显式遍历该链以查找类型为CustomeException1的异常。(尽管您可以:except*是用于使用其API操作捕获的ExceptionGroup的语法糖,包括subgroupsplitderive方法。)

class CustomException1(Exception): pass    
class CustomException2(Exception): pass    
class CustomException3(Exception): pass


def func_1():
    raise CustomException1()


def func_2():
    try:
        func_1()
    except Exception as e:
        raise ExceptionGroup("from func_2", [CustomException2(), e])


def func_3():
    try:
        func_2()
    except ExceptionGroup as eg:
        raise ExceptionGroup("from func3", [CustomException3(), eg])


def func_4():
    try:
        func_3()
    except* CustomException1:
        print("do something specific for CustomException1")
    except* Exception:
        print("general exception handler")

func_4()

当您运行此脚本时,将看到以下输出:

do something specific for CustomException1
general exception handler

请注意,except*子句从可能在层次结构中的任何位置提取CustomException1;捕获器不需要手动解析异常组(尽管可以使用split方法进行解析,这就是except*在其实现中使用的方法)。还要注意,与except不同,except*可以在每个处理程序执行后继续匹配异常。

英文:

Starting in Python 3.11, you can use exception groups to package multiple exceptions into a single package with arbitrary structure. Here, we're still preserving the linear structure implied by the call stack, but we don't need to explicitly traverse that chain to find an exception of type CustomeException1. (Though you can: except* is syntactic sugar for manipulating a caught ExceptionGroup using its API, including the subgroup, split, and derive methods.)

class CustomException1(Exception): pass    
class CustomException2(Exception): pass    
class CustomException3(Exception): pass


def func_1():
    raise CustomException1()


def func_2():
    try:
        func_1()
    except Exception as e:
        raise ExceptionGroup("from func_2", [CustomException2(), e])


def func_3():
    try:
        func_2()
    except ExceptionGroup as eg:
        raise ExceptionGroup("from func3", [CustomException3(), eg])


def func_4():
    try:
        func_3()
    except* CustomException1:
        print("do something specific for CustomException1")
    except* Exception:
        print("general exception handler")

func_4()

When you run the script, you'll see the following output:

do something specific for CustomException1
general exception handler

Note that the except* clause extracts CustomException1 from wherever in the hierarchy it may be found; the catcher need not parse the exception group manually (though it is possible using the split method, which is what except* uses in its implementation.) Also note that unlike except, except* can continue matching exceptions after each handler has executed.

huangapple
  • 本文由 发表于 2023年7月14日 06:25:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76683625.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定