zoukankan      html  css  js  c++  java
  • Python学习————异常处理

    一 什么是异常

    异常是程序发生错误的信号。程序一旦出现错误,便会产生一个异常,若程序中没有处理它,就会抛出该异常,程序的运行也随之终止。在Python中,错误触发的异常如下

    img

    而错误分成两种,一种是语法上的错误SyntaxError,这种错误应该在程序运行前就修改正确

    而错误分成两种,一种是语法上的错误SyntaxError,这种错误应该在程序运行前就修改正确

    >>> if  
      File "<stdin>", line 1
        if
         ^
    SyntaxError: invalid syntax
    

    另一类就是逻辑错误,常见的逻辑错误如

    # TypeError:数字类型无法与字符串类型相加
    1+’2’
    
    # ValueError:当字符串包含有非数字的值时,无法转成int类型
    num=input(">>: ") #输入hello
    int(num)
    
    # NameError:引用了一个不存在的名字x
    x
    
    # IndexError:索引超出列表的限制
    l=['egon','aa']
    l[3]
    
    # KeyError:引用了一个不存在的key
    dic={'name':'egon'}
    dic['age']
    
    # AttributeError:引用的属性不存在
    class Foo:
        pass
    Foo.x
    
    # ZeroDivisionError:除数不能为0
    1/0
    

    异常处理的三个特征:

    异常的追踪信息
    异常的类型
    异常的内容
    

    为何处理异常

    为了增强程序的健壮性,即便是程序运行过程中出错了,也不要终止程序
    而是捕捉异常并处理:将出错信息记录到日志内
    

    如何处理异常?

    1.语法上的错误SyntaxError,
    处理方式一:必须在程序运行前就改正
    # if 1>3
    #     print("run...")
    
    2.逻辑上的错误
    print(x)
    
    # NameError: name 'x' is not defined
    l=['a','b']
    l[2]
    
    # IndexError: list index out of range
    int('abc')
    
    # ValueError: invalid literal for int() with base 10: 'abc'
    dic={'name':'egon'}
    dic['age']
    
    
    # KeyError: 'age'
    class Foo:
        pass
    
    Foo.x
    
    # AttributeError: type object 'Foo' has no attribute 'x'
    

    针对逻辑上的异常又分成两种处理方式

    错误发生的条件是可以预知的,使用if判断来解决
    age=input('>>: ').strip() # 输入的只要不是数字就会出错
    if age.isdigit():
        age=int(age)
        if age > 18:
            print('猜大了')
        elif age < 18:
            print('猜大了')
        else:
            print('猜对了')
    else:
        print('必须输入数字')
    
    错误发生的条件是无法预知的
    print('start...')
    try:
        # 有可能会抛出异常的代码
        子代码1
        子代码2
        子代码3
    except 异常类型1 as e:
        pass
    except 异常类型2 as e:
        pass
    ...
    else:
        如果被检测的子代码块没有异常发生,则会执行else的子代码
    finally:
        无论被检测的子代码块有无异常发生,都会执行finally的子代码
    
    print('end...')
    

    用法一:

    print('start...')
    
    try:
        print('1111111111')
        l=['aaa','bbbb']
        l[3] # 抛出异常IndexError,该行代码同级别的后续代码不会运行
        print('2222222222')
        xxx
        print('33333333')
        dic={'a':1}
        dic['a']
    except IndexError as e:
        print('异常的信息: ',e)
    
    print('end....')
    

    用法二:

    print('start...')
    
    try:
        print('1111111111')
        l=['aaa','bbbb']
        # l[3] # 抛出异常IndexError,该行代码同级别的后续代码不会运行
        print('2222222222')
        xxx
        print('33333333')
        dic={'a':1}
        dic['a']
    except IndexError as e:
        print('异常的信息: ',e)
    except NameError as e:
        print('异常的信息: ',e)
    
    print('end....')
    

    用法三:

    print('start...')
    
    try:
        print('1111111111')
        l = ['aaa', 'bbbb']
        l[3] # 抛出异常IndexError,该行代码同级别的后续代码不会运行
        print('2222222222')
        xxx
        print('33333333')
        dic = {'a': 1}
        dic['aaa']
    # except (IndexError, NameError) as e:
    #     print('异常的信息: ', e)
    # except KeyError as e:
    #     print('字典的key不存在: ', e)
    except Exception as e:  # 万能异常
        print('所有异常都可以匹配的到')
    print('end....')
    

    用法四:else不能单独与try配合使用,必须要搭配except

    print('start...')
    
    try:
        print('1111111111')
        print('2222222222')
        print('33333333')
    except Exception as e:  # 万能异常
        print('所有异常都可以匹配的到')
    else:
        print('====>')
    
    print('end....')
    

    用法五:finally可以单独与try配合使用

    print('start...')
    
    try:
        print('1111111111')
        l = ['aaa', 'bbbb']
        l[3] # 抛出异常IndexError,该行代码同级别的后续代码不会运行
        print('2222222222')
        xxx
        print('33333333')
        dic = {'a': 1}
        dic['aaa']
    finally: # 不处理异常,无论是否发生异常都会执行finally的子代码
        print('====》》》》》应该把被检测代码中回收系统资源的代码放到这里')
    
    print('end....')
    

    异常处理

    为了保证程序的容错性与可靠性,即在遇到错误时有相应的处理机制不会任由程序崩溃掉,我们需要对异常进行处理,处理的基本形式为

    try:
        被检测的代码块
    except 异常类型:
        检测到异常,就执行这个位置的逻辑
    

    举例

    try:
        print('start...')
        print(x) # 引用了一个不存在的名字,触发异常NameError
        print('end...')
    except NameError as e: # as语法将异常类型的值赋值给变量e,这样我们通过打印e便可以知道错误的原因
        print('异常值为:%s' %e)
    print('run other code...')
    
    #执行结果为
    start...
    异常值为:name 'x' is not defined
    run other code...
    

    如果我们想分别用不同的逻辑处理,需要用到多分支的except(类似于多分支的elif,从上到下依次匹配,匹配成功一次便不再匹配其他)

    try:
        被检测的代码块
    except NameError:
        触发NameError时对应的处理逻辑
    except IndexError:
        触发IndexError时对应的处理逻辑
    except KeyError:
        触发KeyError时对应的处理逻辑
    

    举例

    def convert_int(obj):
        try:
            res=int(obj)
        except ValueError as e:
            print('ValueError: %s' %e)
            res=None
        except TypeError as e:
            print('TypeError: %s' %e)
            res=None
        return res
    
    convert_int('egon') # ValueError: invalid literal for int() with base 10: 'egon'
    convert_int({'n':1}) # TypeError: int() argument must be a string, a bytes-like object or a number, not 'dict'
    

    如果我们想多种类型的异常统一用一种逻辑处理,可以将多个异常放到一个元组内,用一个except匹配

    try:
        被检测的代码块
    except (NameError,IndexError,TypeError):
        触发NameError或IndexError或TypeError时对应的处理逻辑
    

    举例

    def convert_int(obj):
        try:
            res=int(obj)
        except (ValueError,TypeError):
            print('argument must be number or numeric string')
            res=None
        return res
    
    convert_int('egon') # argument must be number or numeric string
    convert_int({'n':1}) # argument must be number or numeric string
    

    如果我们想捕获所有异常并用一种逻辑处理,Python提供了一个万能异常类型Exception

    try:
        被检测的代码块
    except NameError:
        触发NameError时对应的处理逻辑
    except IndexError:
        触发IndexError时对应的处理逻辑
    except Exception:
        其他类型的异常统一用此处的逻辑处理
    

    在多分支except之后还可以跟一个else(else必须跟在except之后,不能单独存在),只有在被检测的代码块没有触发任何异常的情况下才会执行else的子代码块

    try:
        被检测的代码块
    except 异常类型1:
        pass
    except 异常类型2:
        pass
    ......
    else:
        没有异常发生时执行的代码块
    

    此外try还可以与finally连用,从语法上讲finally必须放到else之后,但可以使用try-except-finally的形式,也可以直接使用try-finally的形式。无论被检测的代码块是否触发异常,都会执行finally的子代码块,因此通常在finally的子代码块做一些回收资源的操作,比如关闭打开的文件、关闭数据库连接等

    python try: 被检测的代码块 except 异常类型1: pass except 异常类型2: pass ...... else: 没有异常发生时执行的代码块 finally: 无论有无异常发生都会执行的代码块
    

    举例

    f=None
    try:
        f=open(‘db.txt’,'r',encoding='utf-8')
        s=f.read().strip()
        int(s)  # 若字符串s中包含非数字时则会触发异常ValueError
        # f.close() # 若上面的代码触发异常,则根本不可能执行到此处的代码,应该将关闭文件的操作放到finally中
    finally:
        if f: # 文件存在则f的值不为None
            f.close()
    

    在不符合Python解释器的语法或逻辑规则时,是由Python解释器主动触发的各种类型的异常,而对于违反程序员自定制的各类规则,则需要由程序员自己来明确地触发异常,这就用到了raise语句,raise后必须是一个异常的类或者是异常的实例

    class Student:
        def __init__(self,name,age):
            if not isinstance(name,str):
                raise TypeError('name must be str')
            if not isinstance(age,int):
                raise TypeError('age must be int')
    
            self.name=name
            self.age=age
    
    stu1=Student(4573,18) # TypeError: name must be str
    stu2=Student('egon','18') # TypeError: age must be int
    

    在内置异常不够用的情况下,我们可以通过继承内置的异常类来自定义异常类

    class PoolEmptyError(Exception): # 可以通过继承Exception来定义一个全新的异常
        def __init__(self,value='The proxy source is exhausted'): # 可以定制初始化方法
            super(PoolEmptyError,self).__init__()
            self.value=value
    
        def __str__(self): # 可以定义该方法用来定制触发异常时打印异常值的格式
            return '< %s >' %self.value
    
    
    class NetworkIOError(IOError): # 也可以在特定异常的基础上扩展一个相关的异常
        pass
    
    
    raise PoolEmptyError # __main__.PoolEmptyError: < The proxy source is exhausted >
    raise NetworkIOError('连接被拒绝') # __main__.NetworkIOError: 连接被拒绝
    

    最后,Python还提供了一个断言语句assert expression,断定表达式expression成立,否则触发异常AssertionError,与raise-if-not的语义相同,如下

    age='18'
    
    # 若表达式isinstance(age,int)返回值为False则触发异常AssertionError
    assert isinstance(age,int)
    
    # 等同于
    if not isinstance(age,int):
        raise AssertionError
    

    三 何时使用异常处理

    在了解了异常处理机制后,本着提高程序容错性和可靠性的目的,读者可能会错误地认为应该尽可能多地为程序加上try...except...,这其是在过度消费程序的可读性,因为try...except本来就是你附加给程序的一种额外的逻辑,与你的主要工作是没有多大关系的。

    如果错误发生的条件是“可预知的”,我们应该用if来进行”预防”,如下

    age=input('input your age>>: ').strip()
    if age.isdigit(): # 可预知只有满足字符串age是数字的条件,int(age)才不会触发异常,
        age=int(age)
    else:
        print('You must enter the number')
    

    如果错误发生的条件“不可预知”,即异常一定会触发,那么我们才应该使用try...except语句来处理。例如我们编写一个下载网页内容的功能,网络发生延迟之类的异常是很正常的事,而我们根本无法预知在满足什么条件的情况下才会出现延迟,因而只能用异常处理机制了

    import requests
    from requests.exceptions import ConnectTimeout # 导入requests模块内自定义的异常
    
    def get(url):
        try:
            response=requests.get(url,timeout=3)#超过3秒未下载成功则触发ConnectTimeout异常
            res=response.text
        except ConnectTimeout:
            print('连接请求超时')
            res=None
        except Exception:
            print('网络出现其他异常')
            res=None
        return res
    
    get('https://www.python.org')
    

    PS:部分摘自https://zhuanlan.zhihu.com/p/109340070

  • 相关阅读:
    Building fresh packages卡很久
    后端阿里代码扫描
    npm 使用淘宝镜像
    git镜像
    mysql安装8.0.18
    idea2019.2.2版本破解
    JDK下载很慢
    解决GitHub下载速度慢下载失败的问题
    Hashtable多线程遍历问题
    2-18 求组合数 注:代码有问题找不出哪儿错了
  • 原文地址:https://www.cnblogs.com/x945669/p/12715880.html
Copyright © 2011-2022 走看看