本文翻译自:Is it a good practice to use try-except-else in Python?
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 (eg 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
#1楼
参考:https://stackoom.com/question/15iI4/在Python中使用try-except-else是否是一种好习惯
#2楼
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' . Python不赞成将异常仅用于特殊情况的想法,实际上,习惯用法是“要求宽恕,而不是允许” 。 This means that using exceptions as a routine part of your flow control is perfectly acceptable, and in fact, encouraged. 这意味着使用异常作为流程控制的常规部分是完全可以接受的,并且实际上是受鼓励的。
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. 该示例自然有点虚构,但它显示了这种结构的情况。
#3楼
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. 您应该谨慎使用finally块,因为它与try中使用else块的功能不同,除了。 The finally block will be run regardless of the outcome of the try except. 无论try的结果如何,都将运行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"
....:
#4楼
"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 (ie the iterator protocol uses StopIteration to 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. 此外,try-except样式用于防止某些“跨越式”构造固有的竞争条件。 For example, testing os.path.exists results in information that may be out-of-date by the time you use it. 例如,测试os.path.exists会导致信息在您使用时已过时。 Likewise, Queue.full returns information that may be stale. 同样, Queue.full返回的信息可能已过时。 The try-except-else style will produce more reliable code in these cases. 在这种情况下, 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. Python的文化规范有些不同。 In many cases, you must use 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 (ie CPython already implements code for exception checking at every step, regardless of whether you actually use exceptions or not). 另外,在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. 这是其主要目的。
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. 如果没有else子句,那么在最终确定之前运行其他代码的唯一选择就是将代码添加到try子句的笨拙做法。 That is clumsy because it risks raising exceptions in code that wasn't intended to be protected by the try-block. 这很笨拙,因为它冒着在代码中引发异常的危险,而这些异常本来不会受到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. else子句的另一个用例是执行在没有异常发生时必须发生的动作以及在处理异常时不发生的动作。 For example: 例如:
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: 另一个示例发生在单元测试赛跑者中:
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). 最后,在try-block中,else-clause的最常见用法是用于一些美化(在相同的缩进级别上对齐例外结果和非例外结果)。 This use is always optional and isn't strictly necessary. 此用法始终是可选的,并非严格必要。
#5楼
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. 它表明您不太了解Python。 This functionality is encapsulated in the dict.get
method: 此功能封装在dict.get
方法中:
item = d.get('item', 'default')
The try
/ except
block is a much more visually cluttered and verbose way of writing what can be efficiently executing in a single line with an atomic method. try
/ except
块是一种在视觉上更加混乱和冗长的方式,可以用原子方法在一行中有效执行代码。 There are other cases where this is true. 在其他情况下,这是正确的。
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. 不要检查文件是否存在,只需尝试将其打开并捕获相应的IOError。 For the sake of simplicity and readability, try to encapsulate this or factor it out as apropos. 为了简单起见,请尝试将其封装或分解为适当的名称。
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. 阅读Python的Zen ,了解其中存在一些紧绷的原则,并且要警惕过于依赖其中任何一种陈述的教条。
#6楼
OP, YOU ARE CORRECT. OP,您是正确的。 The else after try/except in Python is ugly . 在Python中try / except之后的else很难看 。 it leads to another flow-control object where none is needed: 它导致另一个不需要的流控制对象:
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. 这比else子句清楚得多。 The else after try/except is not frequently written, so it takes a moment to figure what the implications are. 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. 这里只有我的5美分。 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. 我每天对可读性进行投票,而星期日则两次。