美文网首页
认识Python中的异常处理

认识Python中的异常处理

作者: 醉看红尘这场梦 | 来源:发表于2020-03-13 10:08 被阅读0次

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

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

    有哪些常用的异常

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

    • Exception:这是所有异常的基类;
    • AttributeError:访问了不存在的类属性,例如:"Hello world".size
    • IndexError:访问list或者tuple越界,例如:(1, 2)[2]
    • KeyError:访问了dict中不存在的key,例如:{'a':1}['b']
    • NameError:访问了一个不存在的名称,例如:notExist()
    • SyntaxError:很简单,表示语法错误,例如:notExist(
    • TypeError:调用函数的时候传递了类型错误的参数,例如:"Hello".index(1)
    • ValueError:调用函数的时候,传递的参数类型正确,但是值不正确,例如:int('s')
    • ZeroDivisionError:除数为0,例如:3/0

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

    如何处理异常

    接下来,我们来看如何处理这些常见的异常,如果你之前用过任何一种支持面向对象编程的语言,就可以直接把经验移植到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用法,因此,只要知道它就好了。当你看到别人的代码中有这样的用法时,明白它在做什么也就是了。

    相关文章

      网友评论

          本文标题:认识Python中的异常处理

          本文链接:https://www.haomeiwen.com/subject/foqyjhtx.html