如何正确忽略异常

当你只想做一个try——除了而不处理异常时,你在Python中是如何做到的?

下面是正确的做法吗?

try:shutil.rmtree(path)except:pass
1149629 次浏览
try:doSomething()except Exception:pass

try:doSomething()except:pass

不同的是,第二个也会捕获KeyboardInterruptSystemExit和类似的东西,它们直接来自BaseException,而不是Exception

详情见留档:

但是,捕获每个错误通常是不好的做法-请参阅为什么说“除了:通过”是一个糟糕的编程习惯?

当你只想在不处理异常的情况下执行try捕获时,你在Python中是如何做到的?

这取决于你所说的“处理”是什么意思。

如果您打算在不采取任何行动的情况下捕获它,您发布的代码将起作用。

如果您的意思是要对异常执行操作而不阻止异常向上堆栈,那么您需要这样的东西:

try:do_something()except:handle_exception()raise  #re-raise the exact same exception that was thrown

只捕获你感兴趣的错误通常被认为是最佳实践。在shutil.rmtree的情况下,可能是OSError

>>> shutil.rmtree("/fake/dir")Traceback (most recent call last):[...]OSError: [Errno 2] No such file or directory: '/fake/dir'

如果你想默默地忽略这个错误,你会这样做:

try:shutil.rmtree(path)except OSError:pass

为什么?假设您(以某种方式)意外地向函数传递了一个整数而不是字符串,例如:

shutil.rmtree(2)

它会给出错误“TypeError:强制转换为Unicode:需要字符串或缓冲区,int找到”-您可能不想忽略它,这可能很难调试。

如果你想忽略所有的错误,捕获Exception而不是一个简单的except:语句。

不指定异常会捕获异常,包括SystemExit异常,例如sys.exit()使用:

>>> try:...     sys.exit(1)... except:...     pass...>>>

将此与正确退出的以下内容进行比较:

>>> try:...     sys.exit(1)... except Exception:...     pass...shell:~$

如果你想编写更好的代码,OSError异常可以表示各种错误,但在上面的示例中,我们只想忽略Errno 2,所以我们可以更具体:

import errno
try:shutil.rmtree(path)except OSError as e:if e.errno != errno.ENOENT:# ignore "No such file or directory", but re-raise other errorsraise
try:doSomething()except Exception:passelse:stuffDoneIf()TryClauseSucceeds()

仅供参考的是,else子句可以在所有异常之后运行,并且只有在try中的代码不会导致异常时才会运行。

为了完整性:

>>> def divide(x, y):...     try:...         result = x / y...     except ZeroDivisionError:...         print("division by zero!")...     else:...         print("result is", result)...     finally:...         print("executing finally clause")

另请注意,您可以像这样捕获异常:

>>> try:...     this_fails()... except ZeroDivisionError as err:...     print("Handling run-time error:", err)

…然后像这样重新引发异常:

>>> try:...     raise NameError('HiThere')... except NameError:...     print('An exception flew by!')...     raise

此外,多个异常类型可以作为括号元组处理:

try:i_might_fail()except (ValueError, TypeError) as ex:print('I failed with: ', ex)

…或作为单独的除外条款:

try:i_might_fail()except ValueError:print('handling a ValueError...')except TypeError:print('handling a TypeError...')

看到python教程

在Python中,我们处理异常类似于其他语言,但不同之处在于一些语法差异,例如,

try:#Your code in which exception can occurexcept <here we can put in a particular exception name>:# We can call that exception here also, like ZeroDivisionError()# now your code# We can put in a finally block alsofinally:# Your code...

当你只想做一个try捕获而不处理异常时,如何在Python中使用它?

这将帮助您打印异常是什么:(即尝试在不处理异常的情况下捕获并打印异常。)

import systry:doSomething()except:print "Unexpected error:", sys.exc_info()[0]

首先我引用Jack o'Connor的答案这个线程。引用的线程关闭了,所以我在这里写:

“在Python 3.4中有一种新的方法可以做到这一点:

from contextlib import suppress
with suppress(Exception):# your code

这是添加它的提交:http://hg.python.org/cpython/rev/406b47c64480

这是作者Raymond Hettinger,谈论这个和其他各种Python热点:https://youtu.be/OSGv2VnC0go?t=43m23s

我对此的补充是Python 2.7等价物:

from contextlib import contextmanager
@contextmanagerdef ignored(*exceptions):try:yieldexcept exceptions:pass

然后像在Python 3.4中一样使用它:

with ignored(Exception):# your code

如何正确忽略异常?

有几种方法可以做到这一点。

然而,示例的选择有一个简单的解决方案,不包括一般情况。

具体到例子:

而不是

try:shutil.rmtree(path)except:pass

这样做:

shutil.rmtree(path, ignore_errors=True)

这是一个特定于shutil.rmtree的参数。您可以通过执行以下操作看到它的帮助,您将看到它也可以允许错误功能。

>>> import shutil>>> help(shutil.rmtree)

由于这只涵盖了示例的狭窄情况,我将进一步演示如果这些关键字参数不存在,如何处理它。

一般方法

由于上面只涵盖了示例的狭窄情况,我将进一步演示如果这些关键字参数不存在,如何处理它。

Python 3.4中的新功能:

您可以导入suppress上下文管理器:

from contextlib import suppress

但只能抑制最具体的例外:

with suppress(FileNotFoundError):shutil.rmtree(path)

你会默默地忽略一个FileNotFoundError

>>> with suppress(FileNotFoundError):...     shutil.rmtree('bajkjbkdlsjfljsf')...>>>

文档

与任何其他完全抑制异常的机制一样,此上下文管理器应仅用于覆盖非常具体的错误其中默默地继续程序执行被称为做正确的事

请注意,suppressFileNotFoundError仅在Python 3中可用。

如果您希望您的代码也能在Python 2中工作,请参阅下一节:

Python 2&3:

当你只想做一个try/除非而不处理异常时,如何在Python中使用它?

下面是正确的做法吗?

try :shutil.rmtree ( path )except :pass

对于Python 2兼容的代码,pass是拥有无操作语句的正确方式。但是当你做一个裸except:时,这与做except BaseException:相同,其中包括GeneratorExitKeyboardInterruptSystemExit,一般来说,你不想捕获这些东西。

事实上,您应该尽可能具体地命名异常。

这是Python(2)异常层级的一部分,如您所见,如果您捕获更通用的异常,您可以隐藏您没有预料到的问题:

BaseException+-- SystemExit+-- KeyboardInterrupt+-- GeneratorExit+-- Exception+-- StopIteration+-- StandardError|    +-- BufferError|    +-- ArithmeticError|    |    +-- FloatingPointError|    |    +-- OverflowError|    |    +-- ZeroDivisionError|    +-- AssertionError|    +-- AttributeError|    +-- EnvironmentError|    |    +-- IOError|    |    +-- OSError|    |         +-- WindowsError (Windows)|    |         +-- VMSError (VMS)|    +-- EOFError... and so on

您可能想在这里捕获一个OSError,也许您不关心的异常是如果没有目录。

我们可以从errno库中获取特定的错误号,如果没有,则重新提出:

import errno
try:shutil.rmtree(path)except OSError as error:if error.errno == errno.ENOENT: # no such file or directorypasselse: # we had an OSError we didn't expect, so reraise itraise

注意,一个裸提升会引发原始异常,这可能是你在这种情况下想要的。写得更简洁,因为我们真的不需要在异常处理中使用代码显式pass

try:shutil.rmtree(path)except OSError as error:if error.errno != errno.ENOENT: # no such file or directoryraise

我需要忽略多个命令中的错误,混蛋做到了这一点

import fuckit
@fuckitdef helper():print('before')1/0print('after1')1/0print('after2')
helper()

我通常只做:

try:doSomething()except:_ = ""

好吧,如果你喜欢面向对象的编程,这不是一个try-,而是另一种处理异常的方法:

class MyExceptionHandler:
def __enter__(self):... # Do whatever when "with" block is startedreturn self
def __exit__(self, exc_type, exc_value, tb):return True

然后是实际代码:

with MyExceptionHandler():... # Code that may or may not raise an exceptionshutil.rmtree(path)

这个怎么用?

  • __enter__在进入with块时运行。
  • __exit__在退出with块时运行
    • 这应该返回True来沉默可能的异常。
    • 这应该返回None(或被认为是False的东西)以不使潜在的异常沉默。
    • 异常类型、实际异常及其回溯作为(位置)参数传递。您可以使用这些来确定要做什么。

作为最后的说明,更喜欢try-除了。如果你需要比平时更多的抽象,这可能会很有用。