<blockquote>
<p>"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."</p>
</blockquote>
<p>在Python世界中,使用异常进行流控制是常见且正常的</p>
<p>即使是Python核心开发人员也使用异常进行流控制,这种风格在语言中得到了充分的体现(即迭代器协议使用<a href="http://docs.python.org/2.7/library/exceptions.html#exceptions.StopIteration" rel="noreferrer"><em>StopIteration</em></a>来表示循环终止)</p>
<p>此外,try-except样式用于防止某些<a href="http://docs.python.org/2.7/glossary.html#term-lbyl" rel="noreferrer">"look-before-you-leap"</a>构造中固有的竞争条件。例如,测试<a href="http://docs.python.org/2.7/library/os.path.html#os.path.exists" rel="noreferrer"><em>os.path.exists</em></a>会导致信息在您使用时可能已过时。同样,<a href="http://docs.python.org/2.7/library/queue.html#Queue.Queue.full" rel="noreferrer"><em>Queue.full</em></a>返回可能过时的信息。在这些情况下<a href="http://docs.python.org/2.7/glossary.html#term-eafp" rel="noreferrer">try-except-else style</a>将生成更可靠的代码</p>
<blockquote>
<p>"It my understanding that exceptions are not errors, they should only
be used for exceptional conditions"</p>
</blockquote>
<p>在其他一些语言中,这一规则反映了他们的图书馆中反映的文化规范。“规则”还部分基于这些语言的性能考虑</p>
<p>Python文化规范有些不同。在许多情况下,您必须对控制流使用异常。此外,在Python中使用异常不会像在某些编译语言中那样减慢周围代码和调用代码的速度(即<a href="http://en.wikipedia.org/wiki/CPython" rel="noreferrer">CPython</a>已经在每个步骤中实现了异常检查代码,而不管您是否实际使用异常)</p>
<p>换句话说,您对“异常是针对异常的”的理解在其他一些语言中是有意义的,但在Python中是没有意义的</p>
<blockquote>
<p>"However, if it is included in the language itself, there must be a
good reason for it, isn't it?"</p>
</blockquote>
<p>除了有助于避免竞争条件外,异常对于将错误处理拉到循环之外也非常有用。在解释语言中,这是一个必要的优化,因为解释语言往往没有自动<a href="http://en.wikipedia.org/wiki/Loop-invariant_code_motion" rel="noreferrer">loop invariant code motion</a></p>
<p>此外,在处理问题的能力与出现问题的地方相去甚远的常见情况下,异常可以大大简化代码。例如,通常有顶级用户界面代码调用业务逻辑的代码,而业务逻辑又调用低级例程。低级例程中出现的情况(如数据库访问中唯一键的重复记录)只能在顶级代码中处理(如要求用户提供与现有键不冲突的新键)。对此类控制流使用异常允许中级例程完全忽略该问题,并与流控制的这一方面很好地解耦</p>
<p>有一个<a href="http://uberpython.wordpress.com/2012/09/23/why-im-not-leaving-python-for-go/" rel="noreferrer">nice blog post on the indispensibility of exceptions here</a></p>
<p>另外,请参见堆栈溢出回答:<a href="https://stackoverflow.com/questions/180937/are-exceptions-really-for-exceptional-errors">Are exceptions really for exceptional errors?</a></p>
<blockquote>
<p>"What is the reason for the try-except-else to exist?"</p>
</blockquote>
<p>else子句本身很有趣。它在没有异常但在finally子句之前运行。这是其主要目的</p>
<p>如果没有else子句,在完成之前运行其他代码的唯一选项是将代码添加到try子句的笨拙做法。这是笨拙的,因为它有风险
引发代码中不受try块保护的异常</p>
<p>在完成之前运行额外的无保护代码的用例并不经常出现。因此,不要期望在已发布的代码中看到许多示例。这有点罕见</p>
<p>else子句的另一个用例是执行在没有异常发生时必须发生的操作,以及在处理异常时不发生的操作。例如:</p>
<pre class="lang-py prettyprint-override"><code>recip = float('Inf')
try:
recip = 1 / f(x)
except ZeroDivisionError:
logging.info('Infinite result')
else:
logging.info('Finite result')
</code></pre>
<p>另一个例子出现在unittest Runner中:</p>
<pre><code>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='')
</code></pre>
<p>最后,try块中else子句最常见的用法是为了美化(将异常结果和非异常结果在相同的缩进级别上对齐)。这种使用始终是可选的,并非绝对必要</p>