认识Python中的异常处理

2020-03-13  本文已影响0人  醉看红尘这场梦

在现实世界中,无论我们多么小心,编写的代码总是会因为一些外部的原因发生错误。例如,被粗心的开发者传递了错误的参数、要打开的文件被误删除了、操作系统发生了未知错误等等。哪怕这些问题都不存在,用户还可以在你的程序过程中通过Ctrl + C强制结束呢。所以,就像我们要一丝不苟的编写逻辑正确的代码一样,在错误处理上,我们同样马虎不得。

不过好在,相比那些有很多种表达错误方式的语言,Python只有一种表达错误的方式,就是Exception,自然,处理错误的方式,也就只有一种了。

有哪些常用的异常

在开始着手处理异常之前,基于我们已经用到过的内容,来看下Python提供了哪些常用的异常类:

当然,还有一些和操作系统相关的异常,我们也可以自定义异常,这些就都等我们用到的时候再说了。

如何处理异常

接下来,我们来看如何处理这些常见的异常,如果你之前用过任何一种支持面向对象编程的语言,就可以直接把经验移植到Python的错误处理中。我们同样使用try block包围可能会发生错误的代码,但在Python里,我们要使用except捕获希望处理的异常:

try:
    3/0
except ZeroDivisionError:
    print('Divide by zero')

这里要注意,tryexcept语句的末尾,也要使用冒号表示结束。简单来说就是,在Python里,所有需要引入代码块的地方,都需要使用一个冒号表示。

执行一下,就能在控制台看到打印出来的Divide by zero了。如果我们的代码里有多处可能发生异常的地方,就可以把多个except语句并列起来:

try:
    # 3/0
    fn()
except ZeroDivisionError:
    print('Divide by zero')
except NameError:
    print('Invalid name')

或者,你也可以写一个接管所有的异常的默认处理方法,像这样:

try:
    # 3/0
    # fn()
    "Hello".index(1)
except ZeroDivisionError:
    print('Divide by zero')
except NameError:
    print('Invalid name')
except: # This is a too broad exception clause
    print('Default handler')

实际上,我个人并不是很喜欢最后这种像“接盘侠”一样的错误处理方式,当项目中到处充斥着这样的处理方法之后,会隐藏掉很多潜在的异常错误。甚至,有些IDE都会提示你Too broad exception clause

而在下一节中我们会看到,Python中的一个设计准则,叫做Errors should never pass silently,但是显然,这种“万用except”对代码的使用者而言,破坏了这个准则。

理解finally和else

以上,就是Python中处理错误的基本用法。除了每种错误特定的处理代码之外,我们有时还需要在错误发生之后执行一些公共的代码,例如,关闭文件句柄、数据库连接、释放线程锁等等。把这些代码重复写在每个except里显然是不能接受的。为此,Python提供了finally关键字,我们可以这样:

try:
    # 3/0
    fn()
except ZeroDivisionError:
    print('Divide by zero')
except NameError:
    print('Invalid name')
finally:
    print('Clean up actions.')

这次,我们就可以在控制台看到两个消息:Invalid nameClean up actions.。因此,只要记住,把所有事后清理类的代码,都写在finally代码块里,就好了。

实际上,无论错误发生与否,finally block中的代码都会被执行。

但事情至此还没有结束,和for循环类似,Python为try语句也提供了一个else,表示“当try代码块中没有任何错误发生的时候,执行的代码”:

try:
    3/0
except ZeroDivisionError:
    print('Divide by zero')
else:
    print("No errors.")
finally:
    print('Clean up actions.')

在上面这个例子里,由于会发生ZeroDivisionError,因此执行的会是对应的exceptfinallyelse分支并不会执行。但如果我们改成这样:

try:
    3/1
except ZeroDivisionError:
    print('Divide by zero')
else:
    print("No errors.")
finally:
    print('Clean up actions.')

就可以在控制台看到No errors.Clean up actions.这两个消息了。但是,你可能会想,为什么需要else呢?如果try代码块没有异常发生,那把接下来的语句直接写在finally后面不就好了么?

实际上,我也的确没发现特别的合适的这种else用法,因此,只要知道它就好了。当你看到别人的代码中有这样的用法时,明白它在做什么也就是了。

上一篇 下一篇

猜你喜欢

热点阅读