try-except-else存在的原因是什么?
try块允许您处理预期的错误。except块应该只捕获准备处理的异常。如果您处理一个意外错误,您的代码可能会做错误的事情并隐藏bug。
如果没有错误,则执行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
因此,如果我们将else与替代方案(可能会产生错误)进行比较,我们会发现它减少了代码行数,我们可以拥有一个更可读、更可维护、更少错误的代码库。
最后
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是异常对象吗?
不,您不返回异常,只是用一个简单的提升来重新提升它以保留堆栈跟踪。
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
我在这里详细说明我的答案。