【问题标题】:Why isn't my Python exception being re-raised?为什么我的 Python 异常没有被重新引发?
【发布时间】:2020-05-26 07:28:07
【问题描述】:

我在一个模块中有一个函数,它执行如下操作:

def some_func():

    try:
        # do some error-prone thing
        raise ValueError
        return 'calculated foo'
    except AttributeError as err:
        # handle it
        pass
    except:
        print('Some other error happened, let\'s reraise it....')
        raise
    else:
        pass
    finally:
        return 'default foo'

然后在我的主程序中,

try:
    val = some_func()
    print('val=', val)
except:
    print('In main except')
    raise
else:
    print('In main else')
    pass
finally:
    print('And we\'re done')

我的输出是:

发生了一些其他错误,让我们重新提出它....

val= 默认 foo

主要是其他

我们完成了

不会引发异常。

冒着遗漏一些显而易见的东西的风险,为什么ValueError 不在我的主目录中被重新加注?似乎some_func() 中的finally 中的return 导致异常不会被重新引发,但这对我来说似乎很奇怪,我找不到它的任何文档。这是我认为应该发生的事情,想了解我在哪里。

  1. 我在主程序中调用some_func()
  2. some_func() 引发 ValueError
  3. ValueError 在some_func() except 中被捕获,打印“发生其他错误”并重新引发它。
  4. 回到 main,我认为重新引发的 ValueError 应该被 except 捕获,应该打印 'In main except',重新引发,然后异常本身应该未被捕获,导致程序停。但我没有提出任何例外,而是在 else 子句中结束。

【问题讨论】:

  • 如果您希望异常堆栈在执行 finally 块后被解开......为什么它会返回一个值?
  • 这是一个例子,但我的理解是它应该没有区别。从文档中,“如果在 try 子句执行期间发生异常,则异常可以由 except 子句处理。如果异常未由 except 子句处理,则在 finally 子句执行后重新引发异常。”那么我的finally 返回一个与重新提出例外无关的值不是事实吗?
  • 没有。对于您正在尝试做的事情,返回应该在“else”块中,而不是“finally”块中。 Python 将不得不重新引发异常before 返回,因为在返回后异常将不再存在以重新引发。python 可以处理此代码实际上只有两种合理的方式:(1)执行返回,中止任何正在进行的异常堆栈展开,这就是它所做的,或者(2)作为语法错误
  • 实际上,现在我想起来了,如果你给它这个代码,pylint 会在该行给你一个警告

标签: python exception error-handling try-catch


【解决方案1】:

这是预期行为,described in the documentation:

如果存在finally,它指定一个“清理”处理程序。 (...) 如果任何子句发生异常且未处理,则暂时保存该异常。 (...) 如果finally 子句执行returnbreakcontinue 语句,则丢弃保存的异常

【讨论】:

猜你喜欢
  • 2010-11-16
  • 2012-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多