在try块内引发错误的Pythonic方式

6

我有一个检查某些内容的方法,它可以:

  • 自己引发异常
  • 返回 True
  • 返回 False

我想要正确地捕获这个方法可能引发的异常,并在测试返回 False 时也能引发异常。不正确的做法是:

try:
    if not check():
        raise MyException()
except:
    raise MyException()

由于第一个MyExceptionexcept后被捕获了,因此正确处理这种情况的一种方法是

try:
    flag = check()
except:
    raise MyException()
else:
    if not flag:
        raise MyException()

这是唯一处理该情况的方式吗?还是有另外一种更有效的方法来处理它,摆脱 flag 变量?


5
首先,不要使用笼统的 except: 捕获异常,而是只捕获具体的异常。 - Martijn Pieters
@avasal:是什么让你认为 OP 不知道 raise 呢? - Martijn Pieters
你应该在check()中注明所引发的异常,因为正如你从答案中看到的那样:有几种方法可以实现这一点。 - Sebastian Blask
是的,在正常情况下通常总是返回已翻译的文本,除非有特定的例外。但是当您在服务器上运行某些东西时,您不希望由于错误而停止服务器,而是希望将任何错误传播到客户端。 - Alex
3个回答

11

不应该使用 except:,因为它会捕获所有异常,包括 SystemExit,你应该这样做:

try:
    if not check():
        raise MyNewException()
except ExceptionRaisedByCheck:
    raise MyNewException()

如果从check()函数抛出的异常与你想要引发的异常相同,那么你应该进行更改。

编辑:如果异常相同,你也可以简单地执行以下操作(Mark Byers在他的答案中提到过这一点,但现在已经消失了):

if not check():
    raise TheSameException()

如果为 False,则会传播异常或引发异常。


+1 这并不严格回答问题,但在我看来,这个问题并没有被很好地思考。虽然没有更多的背景信息很难确定他想做什么,但这几乎肯定比原帖作者错误地认为是一个好主意要好得多。 - Mark Byers
@MarkByers 你删掉了你的回答?我编辑了我的回答,加入了你的一部分,因为那真的是最简单的解决方案,而我之前没有想到。正如你所说,很难确定目标是什么。 - Sebastian Blask

2
try:
   # whatever
except MyException:
   raise # reraise it
except Exception as e:
   raise MyException(some_info(e)) # unify user-visible exception type

1
在python 3.3中,您可以使用新的{{link1:contextlib.ExitStack上下文管理器}}:
with ExitStack() as stack:
    stack.callback(lambda: raise MyException)

    if check():
        stack.pop_all()

这将引发MyException除非您使用pop_all()清除堆栈回调。
您可以将其编码为自定义上下文管理器:
from contextlib import ExitStack

class ExceptionUnlessCancelled(ExitStack):
    def __init__(self, exception, *args, **kw):
        super(Callback, self).__init__()
        self.exception = exception
        self.callback(self.raiseException, *args, **kwds)

    def raiseException(self, *args, **kw):
        raise self.exception(*args, **kw)

    def cancel(self):
        self.pop_all()

with ExceptionUnlessCancelled(MyException) as exc:
    if check():
        exc.cancel()

看起来有点过度设计,但仍然是一个有趣的解决方案! - Sebastian Blask
@SebastianBlask:我认为上下文管理器是处理复杂异常情况的好方法。对于问题,OP的情况已经被简化了,谁知道还有多少代码围绕着这个检查? - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接