在 Python 中使用 try-except-else 是一个好习惯吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16138232/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it a good practice to use try-except-else in Python?
提问by Juan Antonio Gomez Moriano
From time to time in Python, I see the block:
在 Python 中,我不时看到块:
try:
try_this(whatever)
except SomeException as exception:
#Handle exception
else:
return something
What is the reason for the try-except-else to exist?
try-except-else 存在的原因是什么?
I do not like that kind of programming, as it is using exceptions to perform flow control. However, if it is included in the language, there must be a good reason for it, isn't it?
我不喜欢那种编程,因为它使用异常来执行流控制。但是,如果它包含在语言中,那么它必须有充分的理由,不是吗?
It is my understanding that exceptions are not errors, and that they should only be used for exceptional conditions (e.g. I try to write a file into disk and there is no more space, or maybe I do not have permission), and not for flow control.
我的理解是异常不是错误,它们应该只用于异常情况(例如,我尝试将文件写入磁盘但没有更多空间,或者我可能没有权限),而不是用于流程控制。
Normally I handle exceptions as:
通常我将异常处理为:
something = some_default_value
try:
something = try_this(whatever)
except SomeException as exception:
#Handle exception
finally:
return something
Or if I really do not want to return anything if an exception happens, then:
或者如果我真的不想在发生异常时返回任何东西,那么:
try:
something = try_this(whatever)
return something
except SomeException as exception:
#Handle exception
采纳答案by Raymond Hettinger
"I do not know if it is out of ignorance, but I do not like that kind of programming, as it is using exceptions to perform flow control."
“我不知道是不是出于无知,但我不喜欢这种编程,因为它使用异常来执行流控制。”
In the Python world, using exceptions for flow control is common and normal.
在 Python 世界中,使用异常进行流量控制是常见且正常的。
Even the Python core developers use exceptions for flow-control and that style is heavily baked into the language (i.e. the iterator protocol uses StopIterationto signal loop termination).
甚至 Python 核心开发人员也使用异常进行流控制,这种风格已经深深融入语言中(即迭代器协议使用StopIteration来表示循环终止)。
In addition, the try-except-style is used to prevent the race-conditions inherent in some of the "look-before-you-leap"constructs. For example, testing os.path.existsresults in information that may be out-of-date by the time you use it. Likewise, Queue.fullreturns information that may be stale. The try-except-else stylewill produce more reliable code in these cases.
此外,try-except-style 用于防止某些“look-before-you-leap”构造中固有的竞争条件。例如,测试os.path.exists导致信息在您使用它时可能已经过时。同样,Queue.full返回可能过时的信息。在这些情况下,try-except-else 样式将生成更可靠的代码。
"It my understanding that exceptions are not errors, they should only be used for exceptional conditions"
“我的理解是异常不是错误,它们应该只用于异常情况”
In some other languages, that rule reflects their cultural norms as reflected in their libraries. The "rule" is also based in-part on performance considerations for those languages.
在其他一些语言中,该规则反映了其图书馆中反映的文化规范。“规则”也部分基于这些语言的性能考虑。
The Python cultural norm is somewhat different. In many cases, you mustuse exceptions for control-flow. Also, the use of exceptions in Python does not slow the surrounding code and calling code as it does in some compiled languages (i.e. CPythonalready implements code for exception checking at every step, regardless of whether you actually use exceptions or not).
Python 文化规范有些不同。在许多情况下,您必须对控制流使用异常。此外,在 Python 中使用异常不会像在某些编译语言中那样减慢周围代码和调用代码的速度(即CPython已经在每一步都实现了用于异常检查的代码,无论您是否实际使用异常)。
In other words, your understanding that "exceptions are for the exceptional" is a rule that makes sense in some other languages, but not for Python.
换句话说,您对“例外是例外”的理解在其他一些语言中是有意义的,但对 Python 而言则不然。
"However, if it is included in the language itself, there must be a good reason for it, isn't it?"
“但是,如果它被包含在语言本身中,那么它肯定有一个很好的理由,不是吗?”
Besides helping to avoid race-conditions, exceptions are also very useful for pulling error-handling outside loops. This is a necessary optimization in interpreted languages which do not tend to have automatic loop invariant code motion.
除了有助于避免竞争条件外,异常对于将错误处理拉到循环外也非常有用。这是在解释性语言中的必要优化,这些语言往往不具有自动循环不变代码运动。
Also, exceptions can simplify code quite a bit in common situations where the ability to handle an issue is far removed from where the issue arose. For example, it is common to have top level user-interface code calling code for business logic which in turn calls low-level routines. Situations arising in the low-level routines (such as duplicate records for unique keys in database accesses) can only be handled in top-level code (such as asking the user for a new key that doesn't conflict with existing keys). The use of exceptions for this kind of control-flow allows the mid-level routines to completely ignore the issue and be nicely decoupled from that aspect of flow-control.
此外,在处理问题的能力与问题出现的地方相去甚远的常见情况下,异常可以大大简化代码。例如,通常有顶级用户界面代码调用业务逻辑的代码,而业务逻辑又调用低级例程。低级例程中出现的情况(例如数据库访问中唯一键的重复记录)只能在顶级代码中处理(例如向用户询问与现有键不冲突的新键)。对这种控制流使用异常允许中级例程完全忽略这个问题,并与流控制的那个方面很好地分离。
There is a nice blog post on the indispensibility of exceptions here.
Also, see this Stack Overflow answer: Are exceptions really for exceptional errors?
另外,请参阅此堆栈溢出答案:异常是否真的是异常错误?
"What is the reason for the try-except-else to exist?"
“try-except-else 存在的原因是什么?”
The else-clause itself is interesting. It runs when there is no exception but before the finally-clause. That is its primary purpose.
else 子句本身很有趣。它在没有异常时但在 finally 子句之前运行。这是它的主要目的。
Without the else-clause, the only option to run additional code before finalization would be the clumsy practice of adding the code to the try-clause. That is clumsy because it risks raising exceptions in code that wasn't intended to be protected by the try-block.
如果没有 else 子句,在完成之前运行附加代码的唯一选择就是将代码添加到 try 子句中的笨拙做法。这是笨拙的,因为它有在不打算受 try 块保护的代码中引发异常的风险。
The use-case of running additional unprotected code prior to finalization doesn't arise very often. So, don't expect to see many examples in published code. It is somewhat rare.
在完成之前运行其他不受保护的代码的用例并不经常出现。因此,不要期望在已发布的代码中看到很多示例。这有点罕见。
Another use-case for the else-clause is to perform actions that must occur when no exception occurs and that do not occur when exceptions are handled. For example:
else 子句的另一个用例是执行在没有异常发生时必须发生的操作以及在处理异常时不会发生的操作。例如:
recip = float('Inf')
try:
recip = 1 / f(x)
except ZeroDivisionError:
logging.info('Infinite result')
else:
logging.info('Finite result')
Another example occurs in unittest runners:
另一个例子发生在 unittest runners 中:
try:
tests_run += 1
run_testcase(case)
except Exception:
tests_failed += 1
logging.exception('Failing test case: %r', case)
print('F', end='')
else:
logging.info('Successful test case: %r', case)
print('.', end='')
Lastly, the most common use of an else-clause in a try-block is for a bit of beautification (aligning the exceptional outcomes and non-exceptional outcomes at the same level of indentation). This use is always optional and isn't strictly necessary.
最后,在 try 块中 else 子句的最常见用途是进行一些美化(将异常结果和非异常结果对齐在同一缩进级别)。这种使用始终是可选的,并不是绝对必要的。
回答by Gareth Latty
Python doesn't subscribe to the idea that exceptions should only be used for exceptional cases, in fact the idiom is 'ask for forgiveness, not permission'. This means that using exceptions as a routine part of your flow control is perfectly acceptable, and in fact, encouraged.
Python 不同意异常应该只用于特殊情况的想法,事实上这个习语是“请求宽恕,而不是许可”。这意味着将异常用作流程控制的常规部分是完全可以接受的,实际上也是值得鼓励的。
This is generally a good thing, as working this way helps avoid some issues (as an obvious example, race conditions are often avoided), and it tends to make code a little more readable.
这通常是一件好事,因为以这种方式工作有助于避免一些问题(作为一个明显的例子,竞争条件通常被避免),并且它往往会使代码更具可读性。
Imagine you have a situation where you take some user input which needs to be processed, but have a default which is already processed. The try: ... except: ... else: ...structure makes for very readable code:
想象一下,您有这样一种情况,您接受一些需要处理的用户输入,但有一个已经处理的默认值。该try: ... except: ... else: ...结构使代码非常可读:
try:
raw_value = int(input())
except ValueError:
value = some_processed_value
else: # no error occured
value = process_value(raw_value)
Compare to how it might work in other languages:
与它在其他语言中的工作方式相比:
raw_value = input()
if valid_number(raw_value):
value = process_value(int(raw_value))
else:
value = some_processed_value
Note the advantages. There is no need to check the value is valid and parse it separately, they are done once. The code also follows a more logical progression, the main code path is first, followed by 'if it doesn't work, do this'.
注意优点。不需要检查值是否有效并单独解析它,它们一次完成。代码也遵循更合乎逻辑的进展,主代码路径在前,然后是“如果它不起作用,就这样做”。
The example is naturally a little contrived, but it shows there are cases for this structure.
这个例子自然有点做作,但它显示了这种结构的情况。
回答by Greg
You should be careful about using the finally block, as it is not the same thing as using an else block in the try, except. The finally block will be run regardless of the outcome of the try except.
您应该小心使用 finally 块,因为它与在 try 中使用 else 块不同,除了。无论 try except 的结果如何,finally 块都将运行。
In [10]: dict_ = {"a": 1}
In [11]: try:
....: dict_["b"]
....: except KeyError:
....: pass
....: finally:
....: print "something"
....:
something
As everyone has noted using the else block causes your code to be more readable, and only runs when an exception is not thrown
正如每个人都注意到的那样,使用 else 块会使您的代码更具可读性,并且仅在未引发异常时运行
In [14]: try:
dict_["b"]
except KeyError:
pass
else:
print "something"
....:
回答by Aaron Hall
Is it a good practice to use try-except-else in python?
在 python 中使用 try-except-else 是一个好习惯吗?
The answer to this is that it is context dependent. If you do this:
对此的答案是它取决于上下文。如果你这样做:
d = dict()
try:
item = d['item']
except KeyError:
item = 'default'
It demonstrates that you don't know Python very well. This functionality is encapsulated in the dict.getmethod:
它表明您不太了解Python。该功能封装在dict.get方法中:
item = d.get('item', 'default')
The try/exceptblock is a much more visually cluttered and verbose way of writing what can be efficiently executing in a single line with an atomic method. There are other cases where this is true.
的try/except块是写什么都可以有效地在一行用原子方法执行的视觉上更多混乱和冗长的方式。还有其他情况也是如此。
However, that does not mean that we should avoid all exception handling. In some cases it is preferred to avoid race conditions. Don't check if a file exists, just attempt to open it, and catch the appropriate IOError. For the sake of simplicity and readability, try to encapsulate this or factor it out as apropos.
然而,这并不意味着我们应该避免所有的异常处理。在某些情况下,最好避免竞争条件。不要检查文件是否存在,只需尝试打开它,然后捕获相应的 IOError。为了简单和可读性,尝试将其封装或将其分解为适当的。
Read the Zen of Python, understanding that there are principles that are in tension, and be wary of dogma that relies too heavily on any one of the statements in it.
回答by Kevin J. Rice
OP, YOU ARE CORRECT. The else after try/except in Python is ugly. it leads to another flow-control object where none is needed:
OP,你是对的。 Python 中 try/except 之后的 else 很丑陋。它导致另一个不需要的流控制对象:
try:
x = blah()
except:
print "failed at blah()"
else:
print "just succeeded with blah"
A totally clear equivalent is:
一个完全清楚的等价物是:
try:
x = blah()
print "just succeeded with blah"
except:
print "failed at blah()"
This is far clearer than an else clause. The else after try/except is not frequently written, so it takes a moment to figure what the implications are.
这比 else 子句要清楚得多。try/except 之后的 else 不常被写入,因此需要花点时间弄清楚其含义是什么。
Just because you CAN do a thing, doesn't mean you SHOULD do a thing.
仅仅因为你可以做一件事,并不意味着你应该做一件事。
Lots of features have been added to languages because someone thought it might come in handy. Trouble is, the more features, the less clear and obvious things are because people don't usually use those bells and whistles.
许多功能已添加到语言中,因为有人认为它可能会派上用场。问题是,功能越多,事情越不清晰和明显,因为人们通常不使用这些花里胡哨的东西。
Just my 5 cents here. I have to come along behind and clean up a lot of code written by 1st-year out of college developers who think they're smart and want to write code in some uber-tight, uber-efficient way when that just makes it a mess to try and read / modify later. I vote for readability every day and twice on Sundays.
这里只有我的 5 美分。我必须跟在后面清理很多大学一年级开发人员编写的代码,他们认为自己很聪明,并希望以某种超级紧凑、超级高效的方式编写代码,但那只会让代码变得一团糟稍后尝试阅读/修改。我每天投票支持可读性,周日两次。
回答by Aaron Hall
What is the reason for the try-except-else to exist?
try-except-else 存在的原因是什么?
A tryblock allows you to handle an expected error. The exceptblock should only catch exceptions you are prepared to handle. If you handle an unexpected error, your code may do the wrong thing and hide bugs.
一个try块可以处理预期的错误。该except块应该只捕获您准备处理的异常。如果您处理意外错误,您的代码可能会做错事并隐藏错误。
An elseclause will execute if there were no errors, and by not executing that code in the tryblock, you avoid catching an unexpected error. Again, catching an unexpected error can hide bugs.
一else,如果没有错误子句就会执行,并通过不执行的代码try块,避免受凉意外的错误。同样,捕获意外错误可以隐藏错误。
Example
例子
For example:
例如:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
else:
return something
The "try, except" suite has two optional clauses, elseand finally. So it's actually try-except-else-finally.
“try, except”套件有两个可选子句,else和finally. 所以它实际上是try-except-else-finally。
elsewill evaluate only if there is no exception from the tryblock. It allows us to simplify the more complicated code below:
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
so if we compare an elseto the alternative (which might create bugs) we see that it reduces the lines of code and we can have a more readable, maintainable, and less buggy code-base.
因此,如果我们将 anelse与替代方案(可能会产生错误)进行比较,我们会发现它减少了代码行数,并且我们可以拥有更具可读性、可维护性和错误更少的代码库。
finally
finally
finallywill execute no matter what, even if another line is being evaluated with a return statement.
finally无论如何都会执行,即使正在使用 return 语句评估另一行。
Broken down with pseudo-code
用伪代码分解
It might help to break this down, in the smallest possible form that demonstrates all features, with comments. Assume this syntactically correct (but not runnable unless the names are defined) pseudo-code is in a function.
以尽可能小的形式将其分解,以展示所有功能,并带有注释,这可能会有所帮助。假设这个语法正确(但除非定义了名称,否则不能运行)伪代码在一个函数中。
For example:
例如:
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 hiHyman the return functionality. e.g.:
return True # hiHymans the return in the else clause above
It is true that we couldinclude the code in the elseblock in the tryblock instead, where it would run if there were no exceptions, but what if that code itself raises an exception of the kind we're catching? Leaving it in the tryblock would hide that bug.
确实,我们可以将else块中的代码包含在块中try,如果没有异常,它将在块中运行,但是如果该代码本身引发了我们正在捕获的那种异常怎么办?将它留在try块中会隐藏该错误。
We want to minimize lines of code in the tryblock to avoid catching exceptions we did not expect, under the principle that if our code fails, we want it to fail loudly. This is a best practice.
我们希望尽量减少try块中的代码行数,以避免捕捉到我们没有预料到的异常,其原则是如果我们的代码失败,我们希望它大声失败。这是最佳做法。
It is my understanding that exceptions are not errors
我的理解是异常不是错误
In Python, most exceptions are errors.
在 Python 中,大多数异常都是错误。
We can view the exception hierarchy by using pydoc. For example, in Python 2:
我们可以使用 pydoc 查看异常层次结构。例如,在 Python 2 中:
$ python -m pydoc exceptions
or Python 3:
或 Python 3:
$ python -m pydoc builtins
Will give us the hierarchy. We can see that most kinds of Exceptionare errors, although Python uses some of them for things like ending forloops (StopIteration). This is Python 3's hierarchy:
会给我们层次结构。我们可以看到大多数类型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
A commenter asked:
一位评论者问道:
Say you have a method which pings an external API and you want to handle the exception at a class outside the API wrapper, do you simply return e from the method under the except clause where e is the exception object?
假设您有一个 ping 外部 API 的方法,并且您想在 API 包装器之外的类中处理异常,您是否简单地从 except 子句下的方法返回 e,其中 e 是异常对象?
No, you don't return the exception, just reraise it with a bare raiseto preserve the stacktrace.
不,您不会返回异常,只需用裸重新引发它raise以保留堆栈跟踪。
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
raise
Or, in Python 3, you can raise a new exception and preserve the backtrace with exception chaining:
或者,在 Python 3 中,您可以引发新异常并使用异常链保留回溯:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
raise DifferentException from the_exception
I elaborate in my answer here.
回答by Rajiv Bakulesh Shah
Whenever you see this:
每当你看到这个:
try:
y = 1 / x
except ZeroDivisionError:
pass
else:
return y
Or even this:
甚至这个:
try:
return 1 / x
except ZeroDivisionError:
return None
Consider this instead:
考虑一下:
import contextlib
with contextlib.suppress(ZeroDivisionError):
return 1 / x
回答by zakiakhmad
This is my simple snippet on howto understand try-except-else-finally block in Python:
这是我关于如何理解 Python 中的 try-except-else-finally 块的简单片段:
def div(a, b):
try:
a/b
except ZeroDivisionError:
print("Zero Division Error detected")
else:
print("No Zero Division Error")
finally:
print("Finally the division of %d/%d is done" % (a, b))
Let's try div 1/1:
让我们试试 div 1/1:
div(1, 1)
No Zero Division Error
Finally the division of 1/1 is done
Let's try div 1/0
让我们试试 div 1/0
div(1, 0)
Zero Division Error detected
Finally the division of 1/0 is done
回答by Calculus
See the following example which illustrate everything about try-except-else-finally:
请参阅以下示例,该示例说明了有关 try-except-else-finally 的所有内容:
for i in range(3):
try:
y = 1 / i
except ZeroDivisionError:
print(f"\ti = {i}")
print("\tError report: ZeroDivisionError")
else:
print(f"\ti = {i}")
print(f"\tNo error report and y equals {y}")
finally:
print("Try block is run.")
Implement it and come by:
实施它并通过:
i = 0
Error report: ZeroDivisionError
Try block is run.
i = 1
No error report and y equals 1.0
Try block is run.
i = 2
No error report and y equals 0.5
Try block is run.
回答by hwjp
Just because no-one else has posted this opinion, I would say
仅仅因为没有其他人发表了这个意见,我会说
avoid
elseclauses intry/exceptsbecause they're unfamiliar to most people
避免使用
else从句,try/excepts因为大多数人不熟悉它们
Unlike the keywords try, except, and finally, the meaning of the elseclause isn't self-evident; it's less readable. Because it's not used very often, it'll cause people that read your code to want to double-check the docs to be sure they understand what's going on.
与关键字try、except、 和 不同finally,else子句的含义不是不言而喻的;它的可读性较差。因为它不经常使用,它会导致阅读您的代码的人想要仔细检查文档以确保他们了解正在发生的事情。
(I'm writing this answer precisely because I found a try/except/elsein my codebase and it caused a wtf moment and forced me to do some googling).
(我写这个答案正是因为我try/except/else在我的代码库中找到了一个,它引起了一个 wtf 时刻并迫使我做一些谷歌搜索)。
So, wherever I see code like the OP example:
所以,无论我在哪里看到像 OP 示例这样的代码:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
else:
# do some more processing in non-exception case
return something
I would prefer to refactor to
我宁愿重构为
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
return # <1>
# do some more processing in non-exception case <2>
return something
<1> explicit return, clearly shows that, in the exception case, we are finished working
<2> as a nice minor side-effect, the code that used to be in the
elseblock is dedented by one level.
<1>显式返回,清楚地表明,在异常情况下,我们已经完成工作
<2> 作为一个不错的小副作用,曾经在
else块中的代码被降级了一个级别。

