【问题标题】:Catch multiple exceptions in one line (except block)在一行中捕获多个异常(块除外)
【发布时间】:2011-09-22 03:53:11
【问题描述】:

我知道我能做到:

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

所以,我没有完全成功地捕获这两个不同的异常。

有没有办法做到这一点?

【问题讨论】:

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

标签: python exception exception-handling


【解决方案1】:

来自Python Documentation

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

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

或者,仅适用于 Python 2:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

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

【讨论】:

  • 是否可以将所需的异常存储在可迭代对象中,然后捕获可迭代对象?我正在尝试使用warnings.filterwarnings 将警告列表转换为错误,并且我不想指定警告列表两次。
  • 我确实尝试过...使用list,结果是TypeError。看起来错误必须在 tuple 中才能按预期工作。
  • 不清楚“带括号的元组”是否仅仅是语法上的,还是需要真正的元组。 “Parenthesized”具有误导性,因为您可以在其他地方创建一个不带括号的元组,然后在 except 行中使用它。只有在 except 行中创建时才必须加上括号。
  • @JosephBani,生成器表达式呢?
  • @JosephBani 这根本不是真的。在2 + (x * 2) 中,(x * 2) 肯定不是元组。括号是一个通用的分组结构。元组的定义特征是它包含一个逗号——参见the Python documentation:“请注意,实际上是逗号构成了一个元组,而不是括号。”
【解决方案2】:

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

这样做:

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

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

最佳实践

要以当前和向前兼容 Python 的方式执行此操作,您需要用逗号分隔异常并用括号括起来,以区别于早期通过遵循异常类型将异常实例分配给变量名称的语法用逗号抓住。

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

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 中,err 对象在 except 块结束时超出范围。

已弃用

您可能会看到用逗号分配错误的代码。这种用法是 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 行可以使用 suppress context manager, available in Python 3.4 在一行中处理:

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

所以当你想pass处理某些异常时,使用suppress

【讨论】:

  • 很好地添加了suppress,比在except上执行pass更具可读性
【解决方案3】:

来自Python documentation -> 8.3 Handling Exceptions

try 语句可能有多个 except 子句,用于指定 不同异常的处理程序。最多一个处理程序将是 执行。处理程序只处理发生在 对应的 try 子句,不在同一个 try 的其他处理程序中 陈述。 except 子句可以将多个异常命名为 带括号的元组,例如:

except (RuntimeError, TypeError, NameError):
    pass

请注意,此元组周围的括号是必需的,因为 除了ValueError, e: 是用于通常的语法 在现代 Python 中写成except ValueError as e:(描述 以下)。仍然支持旧语法以实现向后兼容性。 这意味着except RuntimeError, TypeError 不等于 except (RuntimeError, TypeError): 但要except RuntimeError as TypeError: 这不是你想要的。

【讨论】:

    【解决方案4】:

    如果你经常使用大量的异常,你可以预先定义一个元组,这样你就不必多次重新键入它们。

    #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() 中定义它 并在需要的地方传递...

    【讨论】:

      【解决方案5】:

      其中一种方法是..

      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 第二种方法有多个子句,每个子句都调用相同的函数,当您试图不重复自己并为两个例外做同样的事情时,这并不是最好的。 (有关正确方法,请参阅其他答案)。但是,当您想以不同的方式处理异常时,拥有多个 except 子句是正常的。
      • 第二种方式其实很棒
      猜你喜欢
      • 2020-01-28
      • 1970-01-01
      • 2012-01-16
      • 2011-07-30
      • 2010-09-13
      • 1970-01-01
      • 2020-05-10
      相关资源
      最近更新 更多