关于捕获任何异常


695

我如何编写一个try/ except块来捕获所有异常?


4
在大多数情况下,如果您尝试捕获任何异常,则可能做错了什么。我的意思是,您可以仅在代码中拼写错误,甚至不知道它。捕获特定异常是一个好习惯。
vwvolodya 2014年

12
更准确地说,捕获所有可能的异常仅是在静默捕获它们的情况下才是问题。除了将捕获的错误消息打印到sys.stderr并可能记录在何处之外,很难想到此方法还适合什么其他地方。这是完全有效且常见的例外。
Evgeni Sergeev's

你尝试:try: whatever() except Exception as e: exp_capture()
查理·帕克

Answers:


564

您可以,但您可能不应该:

try:
    do_something()
except:
    print "Caught it!"

但是,这也会捕获类似的异常KeyboardInterrupt,您通常不希望那样,对吗?除非您立即重新引发异常-参见docs中的以下示例:

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise


15
您的最后一条陈述是不正确的,您需要明确地说出except Exception:裸露的地方,除非那里也将捕获BaseException。
皮克勒2013年

7
您确实应该打印到stderr。
nyuszika7h

41
我非常强烈不同意“不应该”的说法。您应该谨慎地做。有时候,您在处理第三方库(有时会动态加载!)时会异常地疯狂,并且跟踪所有异常可能是一件非常痛苦的事情,并且如果您只错过其中的一个,您将拥有非常系统中巨大的痛苦错误。话虽这么说,最好尽可能地追踪并适当地处理它们,然后为所有想念的人提供备份。
Blaze

26
我还发现奇怪的是,在不声明实例变量的鸭子输入语言中,突然很担心不输入所有异常。嗯!
Blaze

833

除了裸露的except:子句(就像其他人说的那样,您不应该使用),您可以简单地捕获Exception

import traceback
import logging

try:
    whatever()
except Exception as e:
    logging.error(traceback.format_exc())
    # Logs the error appropriately. 

通常,仅当您想在终止之前处理任何其他未捕获的异常时,才通常考虑在代码的最外层执行此操作。

的优势,except Exception在裸露的except是,有少数例外,它不会赶上,最明显KeyboardInterruptSystemExit:如果你抓住了,吞下这些,那么你可以让任何人都很难离开你的脚本。


我在脑海中有同样的想法,但是它们是一个缺点,假设它们一次被捕获时是两个错误,并且除了您只是打印而已之外,您将退出try块,并且您永远不会知道第二个错误。 。

6
对于任何想知道的人,这完全与我的预期相反,至少在python 2.x中,它仍将捕获非异常子类化的东西,例如ints。
约瑟夫·加文2014年

5
@JosephGarvin,那是不正确的,即,这将不会捕获不子类化的“非异常” Exception。请注意,不可能引发int异常,而尝试引发TypeError异常会引发异常,except Exception在这种情况下,这就是封闭子句所捕获的异常。在另一方面,老式的类可以提出并鉴定为不子类“非例外” Exception-这通过裸捕获except子句,但不是except Exception子句。
Yoel

4
@JosephGarvin检查此博客条目:chris-lamb.co.uk/posts/no-one-expects-string-literal-exception 我与@Yoel在一起,您的测试掩盖了TypeError
Duncan

2
@CharlieParker如果您想要的是捕获它们,那没错,但是您基本上不需要。调用sys.exit()通常意味着您希望该应用程序终止,但是如果您捕获SystemExit,它将不会终止。同样,如果您在正在运行的脚本上按Control-C(在Windows上为Ctrl-break),则您希望程序停止运行,而不是捕获错误并继续运行。但是,如果您想在存在之前进行清理,则可以捕获其中的一个或两个。
邓肯

100

您可以执行此操作以处理一般异常

try:
    a = 2/0
except Exception as e:
    print e.__doc__
    print e.message

8
这可能不会捕获所有异常,因为所有异常的基类是BaseException,而且我遇到了不在Exception类家族中的生产代码。有关详细信息,请参见docs.python.org/3/library/…
DDay

4
这不能捕获所有异常。
Andy_A̷n̷d̷y̷

6
从技术上讲,它应该捕获所有非系统退出的异常。从文档@DDay链接:“ exception BaseException:所有内置异常的基类。它并不意味着要由用户定义的类直接继承(为此,请使用Exception)。” 除非您正在使用忽略此代码的代码,或者需要捕获系统退出的异常,否则应该可以使用上面的代码。
彼得·卡塞塔

@PeterCassetta什么时候想要捕获系统退出的异常?这个问题似乎是我们不想抓住这些问题的共同点,但我不明白为什么。为什么不通常?
查理·帕克

68

要捕获所有可能的异常,请捕获BaseException。它位于Exception层次结构的顶部:

Python 3:https//docs.python.org/3.5/library/exceptions.html#exception-hierarchy

Python 2.7:https//docs.python.org/2.7/library/exceptions.html#exception-hierarchy

try:
    something()
except BaseException as error:
    print('An exception occurred: {}'.format(error))

但是,正如其他人所提到的那样,通常仅在特定情况下才需要此功能。


1
是否希望在按Ctrl-C之后保存长期运行的进度,这很不正常?
BallpointBen

54

非常简单的示例,类似于此处找到的示例:

http://docs.python.org/tutorial/errors.html#defining-clean-up-actions

如果您尝试捕获所有异常,则将所有代码放在“ try:”语句中,代替“ print”执行可能会引发异常的操作。”。

try:
    print "Performing an action which may throw an exception."
except Exception, error:
    print "An exception was thrown!"
    print str(error)
else:
    print "Everything looks great!"
finally:
    print "Finally is called directly after executing the try statement whether an exception is thrown or not."

在上面的示例中,您将按以下顺序查看输出:

1)执行可能会引发异常的动作。

2)无论是否引发异常,在执行try语句后直接调用final。

3)“引发了异常!” 或“一切看起来都很棒!” 取决于是否引发异常。

希望这可以帮助!


26

有多种方法可以做到这一点,特别是在Python 3.0及更高版本中

方法1

这是简单的方法,但不建议使用,因为您不知道确切的代码行实际引发异常:

def bad_method():
    try:
        sqrt = 0**-1
    except Exception as e:
        print(e)

bad_method()

方法2

建议使用此方法,因为它提供了有关每个异常的更多详细信息。这包括:

  • 您代码的行号
  • 文件名
  • 实际错误更详细

唯一的缺点是需要导入tracback。

import traceback

def bad_method():
    try:
        sqrt = 0**-1
    except Exception:
        print(traceback.print_exc())

bad_method()

21

我刚刚发现了这个小技巧,可以测试Python 2.7中的异常名称。有时我已经在代码中处理了特定的异常,因此我需要进行测试以查看该名称是否在已处理的异常列表中。

try:
    raise IndexError #as test error
except Exception as e:
    excepName = type(e).__name__ # returns the name of the exception

2
try:
    whatever()
except:
    # this will catch any exception or error

值得一提的是,这不是正确的Python编码。这还将捕获许多您可能不想捕获的错误。


只是使用,除了不要获取其他答案中提到的所有例外。为此,您必须使用BaseException,但是正如您所说的,没有人应该捕获所有这样的异常。我想如果目标是在开发过程中添加更多粒度,则可以开始,但我认为这不会...
Pyglouthon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.