针对多种例外情况的 DRY 方法

A DRY approach for multiple excepts

提问人:Vova 提问时间:10/27/2023 最后编辑:mkrieger1Vova 更新时间:11/6/2023 访问量:91

问:

假设我们有以下代码:

try:
    whatever
except ValueError:
    something1
except (IndexError, KeyError):
    something2
except KeyBoardInterrupt:
    something3
except Exception:
    something4
else:  # no error
    something5
finally:
    finalize

所以我们有多个例外。我们是否有适合 DRY 方法的其他对立面,因此只有在发生任何错误时才会执行?

例如,我们想设置一些错误变量/标志或记录错误,但除此之外,执行不同的逻辑,而无需编写方法/函数并在每个例外中调用它。except_logic()

python 错误处理

评论

1赞 Charles Duffy 10/27/2023
作为标题,我是否可以建议类似“如果链中的任何异常处理程序触发,则执行操作”?现在,如果不点击,你要求什么并不明显。
0赞 Charles Duffy 10/27/2023
顺便说一句,您没有指定共享逻辑是否需要出现在您的各种 s 之前或之后。如果没关系,那就建议一个解决方案。something
0赞 Vova 10/27/2023
举个例子:我想记录异常,但以不同的方式处理它
3赞 deceze 10/27/2023
如果您想对任何错误执行相同的操作,对特定错误执行特定操作,请有一个并使用 / 检查异常以添加特定处理?exceptisinstancematch
0赞 Vova 10/27/2023
@deceze可能是这样,谢谢,因为现在我无法想象更好的方式

答:

0赞 sudden_appearance 10/27/2023 #1

如果您不关心处理订单,您可以执行以下操作:

error_state = True

try:
    print("Try")  # try raising here to see 'Error occurred'
except ...:
    ...
else:
    print("Else")
    error_state = False
finally:
    if error_state:
        print("Error occurred")

但最好做(更具可读性)

def process_exception(e: Exception):
    # if isinstance(e, type1): ... and so on
    ...


try:
    print("Try")
except Exception as e:
    ...
    # do something common
    ...
    process_exception(e)

评论

0赞 Vova 10/27/2023
这实际上就是我所说的.这不是很舒服,我认为除了使用 isinstance 目前最适合 DRY 之外,还要发表评论except_logic()
0赞 blhsing 10/27/2023 #2

更简洁的方法是使用捕获所有异常处理程序来处理具有相同共享逻辑的任何异常,然后在嵌套异常处理程序中为特定于类型的异常处理逻辑重新引发异常:

try:
    something()
except Exception as e:
    log_exception(e)
    try:
        raise
    except ValueError:
        process_valueerror(e)
    except (IndexError, KeyError):
        process_indexerror_keyerror(e)
    # more shared logics can run here after type-specific logics
    post_processing(e)

演示:https://ideone.com/vlEXtu

您还可以在注释中使用 @deceze 的解决方案,方法是使用语句显式测试异常的类型:if

try:
    something()
except Exception as e:
    log_exception(e)
    if isinstance(e, ValueError):
        process_valueerror(e)
    elif isinstance(e, (IndexError, KeyError)):
        process_indexerror_keyerror(e)
    # more shared logics can run here after type-specific logics
    post_processing(e)

这样可以节省 2 行,因为不必重新引发异常,但同时它添加了调用每个附加错误处理程序的样板,因此这取决于您喜欢哪种方法的个人喜好。isinstance(e, ...)

评论

0赞 Vova 11/6/2023
是的,这个,但不是提高 - 使用 isinstance。我会编辑并接受
0赞 Vova 11/6/2023
编辑失败。(只有我能看到)。好吧,编辑更好
0赞 Vova 11/6/2023
try: something() except Exception as e: log_exception(e) if isinstance(e, ValueError): process_valueerror(e) if isinstance(e, (IndexError, KeyError)): process_indexerror_keyerror(e) # more shared logics can run here after type-specific logics post_processing(e)
0赞 blhsing 11/6/2023
在这种情况下,哪一个更好是一个品味问题。您请求的编辑基于评论中提供的解决方案@deceze。我更喜欢我的解决方案,只是因为嵌套块使代码的意图更清晰恕我直言,因为该结构专用于语言的错误处理。当然,您可以使用该方法节省 2 行,但您还必须为每个额外的错误处理程序重复调用的样板,因此我将使用包含这两种解决方案来更新我的答案。try-excepttry-exceptif..isinstanceisinstance(e, ...)