在一行中捕获多个异常(块除外)


2754

我知道我可以做到:

try:
    # do something that may fail
except:
    # do this if ANYTHING goes wrong

我也可以这样做:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreTooShortException:
    # stand on a ladder

但是,如果我想在两个不同的异常中做同样的事情,那么我现在想到的最好的方法就是:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreBeingMeanException:
    # say please

有什么办法可以做这样的事情(因为在两种情况下都要采取的行动是say please):

try:
    # do something that may fail
except IDontLikeYouException, YouAreBeingMeanException:
    # say please

现在,这确实不起作用,因为它与以下语法匹配:

try:
    # do something that may fail
except Exception, e:
    # say please

因此,我捕捉两个截然不同的异常的努力并未完全实现。

有没有办法做到这一点?


6
请注意,在Python 3中,后者不再是有效的语法。
gerrit

Answers:


3721

Python文档

例如,except子句可以将多个异常命名为带括号的元组。

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

或者,仅对于Python 2:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

用逗号将变量与变量分开仍然可以在Python 2.6和2.7中使用,但是现在已弃用,并且在Python 3中不起作用。现在您应该使用as


9
我确实尝试过...用list,但结果是TypeError。看起来错误必须在中tuple,才能按预期工作。
BallpointBen18年

4
当您清楚地看到在这种情况下需要使用元组时,为什么还要使用列表?
mechanical_meat

6
目前尚不清楚“带括号的元组”仅仅是句法上的还是需要真正的元组。“ Parenthesized”具有误导性,因为您可以在其他地方创建一个没有括号的元组,然后except在行中使用它。如果except在行中创建,则仅需将其括起来。
BallpointBen18年

5
@JosephBani,生成器表达式如何?
jammertheprogrammer

12
@JosephBani根本不是真的。在中2 + (x * 2)(x * 2)肯定不是一个元组。括号是一般的分组结构。元组的定义特征是它包含逗号 -请参阅Python文档:“请注意,实际上是组成元组的逗号,而不是括号。”
索伦·比约恩斯塔德

314

如何在一行中捕获多个异常(块除外)

做这个:

try:
    may_raise_specific_errors():
except (SpecificErrorOne, SpecificErrorTwo) as error:
    handle(error) # might log or have some other default behavior...

由于使用了逗号将错误对象分配给名称的较旧语法,因此需要使用括号。该as关键字用于分配。您可以为错误对象使用任何名称,我error个人更喜欢。

最佳实践

要以当前方式并与Python向前兼容的方式执行此操作,您需要使用逗号分隔Exceptions,并用括号将其包裹起来,以区别于早期的语法,后者通过遵循用逗号。

这是一个简单用法的示例:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError): # the parens are necessary
    sys.exit(0)

我仅指定这些异常以避免隐藏错误,如果遇到错误,我希望从中获得完整的堆栈跟踪。

此处记录:https : //docs.python.org/tutorial/errors.html

您可以将异常分配给变量,(e很常见,但是,如果您需要长时间的异常处理,或者您的IDE像我的一样,仅突出显示比这个更大的选择,那么您可能更喜欢使用更冗长的变量。)实例具有args属性。这是一个例子:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError) as err: 
    print(err)
    print(err.args)
    sys.exit(0)

请注意,在Python 3中,结束errexcept块时该对象不在范围内。

不推荐使用

您可能会看到用逗号分配错误的代码。不赞成使用此用法,它是Python 2.5及更早版本中唯一可用的形式,并且如果您希望代码与Python 3向前兼容,则应更新语法以使用新形式:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError), err: # don't do this in Python 2.6+
    print err
    print err.args
    sys.exit(0)

如果在代码库中看到逗号名称分配,并且您正在使用Python 2.5或更高版本,请切换到新的方式来执行此操作,以便在升级时代码保持兼容。

suppress上下文管理器

可接受的答案实际上是最少4行代码:

try:
    do_something()
except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

tryexceptpass线可以与单线处理抑制上下文管理器,可以在Python 3.4

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

因此,当您想pass在某些例外情况下使用suppress


2
很好的补充的suppress,很多不止做更具可读性passexcept
麻车

50

Python文档-> 8.3处理异常

一条try语句可能具有多个except子句,以指定不同异常的处理程序。最多将执行一个处理程序。处理程序仅处理在相应的try子句中发生的异常,而不处理同一try语句的其他处理程序中的异常。exclude子句可以将多个异常命名为带括号的元组,例如:

except (RuntimeError, TypeError, NameError):
    pass

请注意,必须在该元组周围加上括号,因为除了ValueError, e:用于except ValueError as e:现代Python中通常编写的语法(如下所述)外,其他语法都是这样。为了向后兼容,仍旧支持旧语法。这意味着except RuntimeError, TypeError不等于 except (RuntimeError, TypeError):except RuntimeError as TypeError:不是您想要的。


35

如果您经常使用大量异常,则可以预定义一个元组,因此不必多次重新键入它们。

#This example code is a technique I use in a library that connects with websites to gather data

ConnectErrs  = (URLError, SSLError, SocketTimeoutError, BadStatusLine, ConnectionResetError)

def connect(url, data):
    #do connection and return some data
    return(received_data)

def some_function(var_a, var_b, ...):
    try: o = connect(url, data)
    except ConnectErrs as e:
        #do the recovery stuff
    blah #do normal stuff you would do if no exception occurred

笔记:

  1. 如果您还需要捕获除预定义元组中的异常以外的其他异常,则需要定义另一个except块。

  2. 如果您不能忍受全局变量,请在main()中定义它,并在需要的地方传递它...


17

一种方法是..

try:
   You do your operations here;
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list, 
   then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

另一种方法是创建一种方法,该方法执行由except块执行的任务,并在except您编写的所有块中调用它。

try:
   You do your operations here;
   ......................
except Exception1:
    functionname(parameterList)
except Exception2:
    functionname(parameterList)
except Exception3:
    functionname(parameterList)
else:
   If there is no exception then execute this block. 

def functionname( parameters ):
   //your task..
   return [expression]

我知道第二种方法并不是做到这一点的最佳方法,但我只是在说明一些实现此目的的方法。


我之所以使用第二个,是因为我有两个不同的例外,每个例外都需要进行不同的处理。这样做有什么问题吗?
majikman

@majikman当您尝试不重复自己并为两个异常做相同的事情时,第二个方法包含多个子句,每个子句都调用同一函数并不是最好的方法。(有关正确方法,请参见其他答案)。但是,except当您想不同地处理异常时,具有多个子句是正常的。
同名的
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.