try语句的可选else子句的预期用途是什么?


当前回答

假设您的编程逻辑取决于字典中是否有具有给定键的条目。你可以使用if…来测试dict.get(key)的结果。其他的……或者你可以这样做:

try:
    val = dic[key]
except KeyError:
    do_some_stuff()
else:
    do_some_stuff_with_val(val)

其他回答

PEP 380中有一个很好的try-else示例。基本上,它归结为在算法的不同部分做不同的异常处理。

大概是这样的:

try:
    do_init_stuff()
except:
    handle_init_suff_execption()
else:
    try:
        do_middle_stuff()
    except:
        handle_middle_stuff_exception()

这允许您在异常发生的地方编写异常处理代码。

Python try-else try语句的可选else子句的预期用途是什么?

其预期用途是,如果没有预期要处理的异常,则为运行更多代码提供上下文。

这个上下文避免意外处理您没有预料到的错误。

但是理解导致else子句运行的确切条件非常重要,因为return、continue和break可以中断到else的控制流。

总之

如果没有异常,并且没有被return、continue或break语句中断,else语句将运行。

其他答案忽略了最后一部分。

从文档中可以看出:

类型的控件流出时,执行可选的else子句 try子句结束

(粗体)。脚注写道:

*目前,控制“从末端流出”,除非在 异常或return、continue或break语句的执行。

它至少需要一个except子句(参见语法)。所以它实际上不是“try-else”,而是“try-except-else(-finally)”,其中else(和finally)是可选的。

Python教程详细说明了预期的用法:

The try ... except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. For example: for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close() The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try ... except statement.

示例区分else和try块后面的代码

如果处理错误,else块将不会运行。例如:

def handle_error():
    try:
        raise RuntimeError('oops!')
    except RuntimeError as error:
        print('handled a RuntimeError, no big deal.')
    else:
        print('if this prints, we had no error!') # won't print!
    print('And now we have left the try block!')  # will print!

现在,

>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!

可以在finally子句中以通用的方式使用此构造来处理异常,而在没有异常时执行其他操作:

class TooManyRetries(RuntimeError):
    pass


n_tries = 0
max_retries = 2
while True:
    try:
        n_tries += 1
        if n_tries >= max_retries:
            raise TooManyRetries
        fail_prone_operation()
    except Exception1 as ex:
        # handle1
    except Exception2 as ex:
        # handle2
    except Exception3 as ex:
        # handle3
    except TooManyRetries as ex:
        raise
    else: # No exception
        n_tries = 0
    finally:
        common_restore_state()
        continue

    

我能想到的一种使用场景是不可预测的异常,如果您再次尝试,可以避免这种异常。例如,当try块中的操作涉及随机数时:

while True:
    try:
        r = random.random()
        some_operation_that_fails_for_specific_r(r)
    except Exception:
        continue
    else:
        break

但是如果可以预测异常,则应该始终在异常之前选择验证。然而,并不是所有的事情都可以预测,所以这种代码模式有它的一席之地。

Try-except-else非常适合结合EAFP模式和duck-typing:

try:
  cs = x.cleanupSet
except AttributeError:
  pass
else:
  for v in cs:
    v.cleanup()

您可能认为naïve代码是好的:

try:
  for v in x.cleanupSet:
    v.clenaup()
except AttributeError:
  pass

这是在代码中意外隐藏严重错误的好方法。我在那里输入了清理,但是让我知道的AttributeError正在被吞噬。更糟糕的是,如果我写对了,但清理方法偶尔被传递一个具有错误命名属性的用户类型,导致它在中途无声地失败并留下一个未关闭的文件,会怎样?祝你在调试时好运。