zoukankan      html  css  js  c++  java
  • Python核心技术与实战——六|异常处理

    和其他语言一样,Python中的异常处理是很重要的机制和代码规范。

    一.错误与异常

      通常来说程序中的错误分为两种,一种是语法错误,另一种是异常。首先要了解错误和异常的区别和联系。

      语法错误比较容易理解,就是写的代码不符合变成规范,无法被识别或执行,就像这样

    >>> print(name)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'name' is not defined

    由于name这个变量在被调用前没有被声明,在被调用时就会报错。或者if语句后遗漏了冒号、缩进错误等等。

      而异常则是指程序可以正常执行,但是在执行过程会遇到错误然后抛出异常,比如这样

    >>> l = [1,2,3]
    >>> l + 2
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can only concatenate list (not "int") to list
    >>> 10/0
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ZeroDivisionError: division by zero
    >>> dic = {'name':'123'}
    >>> dic['age']
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyError: 'age'

    上面的例子中出现了三种异常,分别是类型错误、除数不能为0和字典键错误。异常种类还有很多很多中,其他的可以查询异常的官方文档

    二.异常的处理

      如果程序在执行中某处跑到了异常,程序就会终止并退出,而有些时候我们是不想让程序停止的,这时候就要用到异常处理了,通常使用try和except来实现。比如这样:

    while True:
        a = input('a:')
        b = input('b:')
        try:
            a = float(a)
            b = float(b)
            print('a/b={}'.format(a/b))
        except ZeroDivisionError as e:
            print(e)

      这样当输入的b值为0时,程序就会抛出异常并打印出来

    a:1
    b:0
    float division by zero

      但是,except block只能catch和列出来的异常匹配的异常类型,当输入的a或b是非数字字符串时,还是会报错后程序终止并退出。

    a:a
    b:2
    Traceback (most recent call last):
      File "D:/python/Python核心技术实战/异常处理.py", line 6, in <module>
        a = float(a)
    ValueError: could not convert string to float: 'a'

      解决方法有两种,一种就是把可能会出现等待异常就要把两种异常都列出来,比如这样

    while True:
        a = input('a:')
        b = input('b:')
        try:
            a = float(a)
            b = float(b)
            print('a/b={}'.format(a/b))
        except (ZeroDivisionError,ValueError) as err:
            print(err)

      或者分开来写

    while True:
        a = input('a:')
        b = input('b:')
        try:
            a = float(a)
            b = float(b)
            print('a/b={}'.format(a/b))
        except ZeroDivisionError as err:
            print('ZeroDivisionError:{}'.format(err))
        except ValueError as err:
            print('ValueError:{}'.format(err))

      这样,在程序执行的时候,except block中只要有一个exception类型与之实际匹配就可以。

      不过在大多数时候我们很难保证程序能覆盖所有的异常类型,所以通常的做法实在最后加一个except block,声明的异常类型时Exception。Exception是所有非系统异常的基类,能够匹配所有非胸痛异常。所以代码应该是这样的

    while True:
        a = input('a:')
        b = input('b:')
        try:
            a = float(a)
            b = float(b)
            print('a/b={}'.format(a/b))
        except ZeroDivisionError as err:
            print('ZeroDivisionError:{}'.format(err))
        except ValueError as err:
            print('ValueError:{}'.format(err))
        except Exception as err:
            print('Other error:{}'.format(err))

      或者在except后面省略异常类型,表示与任意异常匹配(包括系统异常)。

    except:
        print('Other error')

      这里有个点要注意一下:如果程序中存在多个except block时,最多只能由一个block被catch,,也就是说只有最前面的那个block会执行,后面的就被忽略了。

    三.finally的用法

      在异常处理中还有一个最常用的方法是finally,它经常和try、except一起使用,无论前面发生什么情况,finally block中的语句都会执行。即便前面的block中由return。一个常见的场景就是对文件的读取操作

    try:
        f = open('file.txt','r')
    except OSError as err:
        print(err)
    except:
        print('Unexpected error')
    finally:
        f.close()

    不管前面执行了什么操作,最后都是要关闭文件,从而确保文件的完整性。所以,在finally中,我们会放置一些无论如何都要执行的语句。其实针对上面这个对文件进行操作的例子,在前面的用法是用with open语法,在with open最后会自动关闭文件使代码看起来更整洁。

    四.用户自定义异常

      上面的例子里已经列举了几种Python内置的异常类型,还给出了官方的文档。其实我们还可以自己定义异常类型

    class MyInputError(Exception):
        def __init__(self,value):
            self.value = value
        def __str__(self):      #自定义异常的string表达式
            return ('{} is invalid input'.format(repr(self.value)))
    try:
        raise MyInputError(123)    #直接抛出异常
    except MyInputError as err:
        print('error:{}'.format(err))

      这里我们还用了raise来直接抛出异常。其实Python的内置异常种类通常来说已经够用了!正常情况不需要用户自己定义!

    五.异常的使用场景与注意点

      这一段里我们要着重来看一下异常的使用场景和注意点:

      通常来说,如果我们不确定某段代码能否成功执行,往往这里就需要加上异常处理比如我们从database里获取了一个key-value结构的数据,在一般的网站后台这种数据都是经过json序列化后的字符串,我们要想获得数据就需要将字符串decode。

    import json
    raw_data = queryDB(uid)   #获取json序列化后的字符串数据
    data = json.loads(raw_data)

      在json.loads()函数中如果输入的字符串不符合其规范,就无法解码,程序会抛出异常,这个时候加上异常处理就显得非常重要。

      但是我们还要避免走向另一个极端:滥用异常处理

    data = {'name':'jack',
            'age':22}
    try:
        data['job']
    
    except KeyError as err:
        print('KeyError:{}'.format(err))

      这样的代码其实是没问题的,但是显得有冗余,一般是没有人这么用的。直接这样用就可以了

    if 'job' in data:
        data['job']

      更简单的,直接这样写

    data.get('job')

      所以,一般的flow-control(流程控制)的代码逻辑,我们一般是不用异常处理的

  • 相关阅读:
    "废物利用"也抄袭——“完全”DIY"绘图仪"<三、上位机程序设计>
    "废物利用"也抄袭——“完全”DIY"绘图仪"<二、下位机程序设计>
    "废物利用"也抄袭——“完全”DIY"绘图仪"<一、准备工作>
    我还活着,我回来了
    链表的基础操作专题小归纳
    文件的基础操作专题小归纳
    正整数序列 Help the needed for Dexter ,UVa 11384
    偶数矩阵 Even Parity,UVa 11464
    洛谷-跑步-NOI导刊2010提高
    洛谷-关押罪犯-NOIP2010提高组复赛
  • 原文地址:https://www.cnblogs.com/yinsedeyinse/p/11184667.html
Copyright © 2011-2022 走看看