try-except-else 存在的原因是什么?
try
块允许您处理预期的错误。该except
块应该只捕获您准备处理的异常。如果您处理意外错误,您的代码可能会做错事并隐藏错误。
else
如果没有错误,将执行一个子句,并且通过不在try
块中执行该代码,您可以避免捕获意外错误。同样,捕获意外错误可以隐藏错误。
例子
例如:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
else:
return something
“try, except”套件有两个可选子句,else
和finally
. 所以实际上是try-except-else-finally
。
else
仅当块没有异常时才会评估try
。它允许我们简化下面更复杂的代码:
no_error = None
try:
try_this(whatever)
no_error = True
except SomeException as the_exception:
handle(the_exception)
if no_error:
return something
因此,如果我们将 anelse
与替代方案(可能会产生错误)进行比较,我们会发现它减少了代码行数,并且我们可以拥有一个更具可读性、可维护性和更少错误的代码库。
finally
finally
无论如何都会执行,即使正在使用 return 语句评估另一行。
用伪代码分解
它可能有助于将其分解,以尽可能最小的形式展示所有功能,并附上注释。假设这个语法正确(但除非名称已定义,否则不可运行)伪代码在函数中。
例如:
try:
try_this(whatever)
except SomeException as the_exception:
handle_SomeException(the_exception)
# Handle a instance of SomeException or a subclass of it.
except Exception as the_exception:
generic_handle(the_exception)
# Handle any other exception that inherits from Exception
# - doesn't include GeneratorExit, KeyboardInterrupt, SystemExit
# Avoid bare `except:`
else: # there was no exception whatsoever
return something()
# if no exception, the "something()" gets evaluated,
# but the return will not be executed due to the return in the
# finally block below.
finally:
# this block will execute no matter what, even if no exception,
# after "something" is eval'd but before that value is returned
# but even if there is an exception.
# a return here will hijack the return functionality. e.g.:
return True # hijacks the return in the else clause above
确实,我们可以将块中的代码包含在else
块中try
,如果没有异常,它将运行在哪里,但是如果该代码本身引发了我们正在捕获的那种异常怎么办?将它留在try
块中会隐藏该错误。
我们希望尽量减少try
块中的代码行数以避免捕获我们没有预料到的异常,原则是如果我们的代码失败,我们希望它大声失败。这是一个最佳实践。
我的理解是异常不是错误
在 Python 中,大多数异常都是错误。
我们可以使用 pydoc 查看异常层次结构。例如,在 Python 2 中:
$ python -m pydoc exceptions
或 Python 3:
$ python -m pydoc builtins
会给我们层次结构。我们可以看到大多数类型Exception
都是错误,尽管 Python 将其中一些用于结束for
循环 ( StopIteration
) 之类的事情。这是 Python 3 的层次结构:
BaseException
Exception
ArithmeticError
FloatingPointError
OverflowError
ZeroDivisionError
AssertionError
AttributeError
BufferError
EOFError
ImportError
ModuleNotFoundError
LookupError
IndexError
KeyError
MemoryError
NameError
UnboundLocalError
OSError
BlockingIOError
ChildProcessError
ConnectionError
BrokenPipeError
ConnectionAbortedError
ConnectionRefusedError
ConnectionResetError
FileExistsError
FileNotFoundError
InterruptedError
IsADirectoryError
NotADirectoryError
PermissionError
ProcessLookupError
TimeoutError
ReferenceError
RuntimeError
NotImplementedError
RecursionError
StopAsyncIteration
StopIteration
SyntaxError
IndentationError
TabError
SystemError
TypeError
ValueError
UnicodeError
UnicodeDecodeError
UnicodeEncodeError
UnicodeTranslateError
Warning
BytesWarning
DeprecationWarning
FutureWarning
ImportWarning
PendingDeprecationWarning
ResourceWarning
RuntimeWarning
SyntaxWarning
UnicodeWarning
UserWarning
GeneratorExit
KeyboardInterrupt
SystemExit
一位评论者问道:
假设您有一个 ping 外部 API 的方法,并且您想在 API 包装器之外的类中处理异常,您是否只需从 except 子句下的方法中返回 e,其中 e 是异常对象?
不,您不返回异常,只需用裸露的方式重新引发它raise
以保留堆栈跟踪。
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
raise
或者,在 Python 3 中,您可以引发新异常并使用异常链保留回溯:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
raise DifferentException from the_exception
我在这里详细说明我的答案。