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

805 投票
22 回答
488294 浏览
提问于 2025-04-15 11:33

try语句中,可选的else部分是用来做什么的呢?

22 个回答

82

Python中的try-else

try语句中的可选else部分的用途是什么呢?

它的主要目的是在没有出现预期中的错误时,提供一个地方让更多的代码运行。

这样可以避免意外处理那些你没有预料到的错误。

不过,理解导致else部分运行的具体条件是很重要的,因为returncontinuebreak会打断控制流,导致不执行else

总结一下

只有在没有出现任何异常,并且没有被returncontinuebreak打断的情况下,else语句才会执行。

其他回答忽略了最后这一点。

来自文档:

可选的else部分在控制流“流出”try部分的末尾时执行。

(加粗部分是强调的。) 脚注中写道:

*目前,控制流“流出末尾”除非出现异常,或者执行了returncontinuebreak语句。

它确实需要至少有一个前面的except部分(见语法)。所以它其实不是“try-else”,而是“try-except-else(-finally)”,其中else(和finally)是可选的。

Python教程详细说明了它的用途:

try ... except语句有一个可选的else部分,当它存在时,必须跟在所有except部分之后。它适用于在try部分没有引发异常时必须执行的代码。例如:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except OSError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

使用else部分比在try部分添加额外代码要好,因为它可以避免意外捕获那些没有被try ... except语句保护的代码引发的异常。

示例:区分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!
154

使用 else 的一个重要原因是风格和可读性。通常,把可能引发错误的代码放在处理这些错误的代码附近是个好主意。比如,看看这两个例子:

try:
    from EasyDialogs import AskPassword
    # 20 other lines
    getpass = AskPassword
except ImportError:
    getpass = default_getpass

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
else:
    # 20 other lines
    getpass = AskPassword

第二个例子在 except 不能提前返回或者重新抛出错误时是比较好的。如果可以的话,我会这样写:

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
    return False  # or throw Exception('something more descriptive')

# 20 other lines
getpass = AskPassword

注意:这个回答是从最近发布的重复问题中复制过来的,详细内容可以在 这里找到,所以里面提到的“AskPassword”相关内容也是如此。

1076

try块的代码执行完后,如果没有出现任何错误,else块里的代码就会被执行。老实说,我自己用到这个的机会不多。

不过,处理异常中提到:

使用else子句比在try块中添加额外的代码要好,因为这样可以避免意外捕获到不是由try ... except保护的代码引发的异常。

所以,如果你有一个方法可能会抛出IOError,你想捕获它引发的异常,但如果第一个操作成功后你还想做其他事情,并且你不想捕获那个操作中的IOError,你可以这样写:

try:
    operation_that_can_throw_ioerror()
except IOError:
    handle_the_exception_somehow()
else:
    # we don't want to catch the IOError if it's raised
    another_operation_that_can_throw_ioerror()
finally:
    something_we_always_need_to_do()

如果你只是把another_operation_that_can_throw_ioerror()放在operation_that_can_throw_ioerror后面,except会捕获第二个调用的错误。如果你把它放在整个try块的后面,它会一直被执行,直到finally之后才会执行。使用else可以确保:

  1. 第二个操作只有在没有异常时才会执行,
  2. 它在finally块之前执行,
  3. 它引发的任何IOError不会在这里被捕获。

撰写回答