try

    让我们用一个例子来看看 try 的机制:

    try:

    print('try…')

    r = 10 / 0

    print('result:', r)

    except ZeroDivisionError as e:

    print('except:', e)

    finally:

    print('finally…')

    print('END')

    当我们认为某些代码可能会出错时,就可以用 try 来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即 except 语句块,执行完 except 后,如果有 finally 语句块,则执行 finally 语句块,至此,执行完毕。

    上面的代码在计算 10 / 0 时会产生一个除法运算错误:

    try…

    except: division by zero

    finally…

    END

    从输出可以看到,当错误发生时,后续语句 print('result:', r) 不会被执行, except 由于捕获到 ZeroDivisionError ,因此被执行。最后, finally 语句被执行。然后,程序继续按照流程往下走。

    如果把除数 0 改成 2 ,则执行结果如下:

    try…

    result: 5

    finally…

    END

    由于没有错误发生,所以 except 语句块不会被执行,但是 finally 如果有,则一定会被执行(可以没有 finally 语句)。

    你还可以猜测,错误应该有很多种类,如果发生了不同类型的错误,应该由不同的 except 语句块处理。没错,可以有多个 except 来捕获不同类型的错误:

    try:

    print('try…')

    r = 10 / int('a')

    print('result:', r)

    except ValueError as e:

    print('ValueError:', e)

    except ZeroDivisionError as e:

    print('ZeroDivisionError:', e)

    finally:

    print('finally…')

    print('END')

    int() 函数可能会抛出 ValueError ,所以我们用一个 except 捕获 ValueError ,用另一个 except 捕获 ZeroDivisionError

    此外,如果没有错误发生,可以在 except 语句块后面加一个 else ,当没有错误发生时,会自动执行 else 语句:

    try:

    print('try…')

    r = 10 / int('2')

    print('result:', r)

    except ValueError as e:

    print('ValueError:', e)

    except ZeroDivisionError as e:

    print('ZeroDivisionError:', e)

    else:

    print('no error!')

    finally:

    print('finally…')

    print('END')

    Python的错误其实也是class,所有的错误类型都继承自 BaseException ,所以在使用 except 时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。比如:

    try:

    foo()

    except ValueError as e:

    print('ValueError')

    except UnicodeError as e:

    print('UnicodeError')

    第二个 except 永远也捕获不到 UnicodeError ,因为 UnicodeError ValueError 的子类,如果有,也被第一个 except 给捕获了。

    Python所有的错误都是从 BaseException 类派生的,常见的错误类型和继承关系看这里:

    https://docs.python.org/3/library/exceptions.html#exception-hierarchy

    使用 try…except 捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数 main() 调用 foo() foo() 调用 bar() ,结果 bar() 出错了,这时,只要 main() 捕获到了,就可以处理:

    def foo(s):

    return 10 / int(s)



    def bar(s):

    return foo(s) * 2



    def main():

    try:

    bar('0')

    except Exception as e:

    print('Error:', e)

    finally:

    print('finally…')

    也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写 try…except…finally 的麻烦。