Python函数末尾的"raise"在"try"或"except"块外
如果raise
不在try
或except
的代码块里,而只是作为函数的最后一条语句,它会发生什么呢?
def foo(self):
try:
# some code that raises an exception
except Exception as e:
pass
# notice that the "raise" is outside
raise
这个例子打印了1,但没有打印2,所以可以推测最后的raise
语句只是重新抛出了最后一个发生的异常。
def foo():
try:
raise Exception()
except Exception as e:
pass
print 1
raise
print 2
if __name__ == '__main__':
foo()
有没有关于这种用法的官方文档呢?
5 个回答
我遇到过一个问题,想要在函数没有返回值的情况下,把之前捕获的错误再抛出来。于是我查了一下 sys
和 traceback
这两个模块,但没找到合适的方法,所以最后我选择在代码块外面存储这个错误。
def foo():
caught = None
try:
raise Exception
except Exception as e:
caught = e
pass
raise caught
f = foo()
输出
Traceback (most recent call last):
line 13, in <module>
line 10, in foo
line 5, in foo
Exception
虽然在上面的例子中这样做没什么用,但如果你需要在循环中尝试很多次并且重新抛出错误,这个方法就很有用了。我具体的需求是实现一个HTTP请求的重试机制。
import time
def foo(key):
caught = None
for i in [1, 2, 3, 4, 5]:
try:
return d[key]
except KeyError as e:
caught = e
print(i)
time.sleep(i)
continue
raise caught
d = {"bar": "baz"}
f = foo(key="baz")
输出
1
2
3
4
5
Traceback (most recent call last):
line 19, in <module>
line 15, in foo
line 8, in foo
KeyError: 'baz'
简单的说,使用“bare raise”会重新抛出当前的异常。通常在一个函数的最后使用它是没有意义的,除非这个函数是在处理异常的情况下被调用的:
单独使用“raise”是无效的,这时Python会抛出自己的异常。
>>> def x():
... raise
>>> x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in x
TypeError: exceptions must be old-style classes or derived from BaseException, not NoneType
但是如果在异常处理块中调用它,它的表现就正常了。
>>> try:
... int('a')
... except:
... x()
...
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'a'
>>>
编辑
如果这个函数是在尝试进行某种恢复操作,这样做可能是合理的。这个函数可以修复出错的地方,记录一条信息,触发灭火器等等……如果它仍然认为系统有问题,就可以使用raise
。
一个简单的 raise
语句会重新抛出最后捕获到的异常。你可以在这里了解更多信息:https://docs.python.org/2/tutorial/errors.html#raising-exceptions
正如Russell所说,
一个简单的
raise
语句会重新抛出最后捕获到的异常。
这不管是在try-except块里还是外面都没关系。如果之前捕获到了一个异常,那么调用raise
就会重新抛出这个异常。否则,Python会报错,告诉你之前捕获的异常是None
,并抛出一个TypeError
,因为None
并不是一个可以被抛出的东西。
正如tdelaney所说,除了在处理错误的函数中,这样做似乎没有什么意义。个人觉得,这种用法甚至不应该出现在错误处理函数里,因为raise
应该仍然放在except
块中。有人可能会试图用这个来执行代码,无论是否发生错误,但使用finally
块才是正确的做法。另一种可能是用这个来判断在执行函数时是否发生了错误,但其实有更好的方法来做到这一点,比如返回一个额外的值来指示是否发生了错误或发生在哪里。