• 异常处理


    1.什么是异常

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

    三个特征
    异常的追踪信息
    异常类型
    异常的值
    

    image-20211023113334930

    而错误分成两种,一种是语法上的错误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
    

    2.为什么要处理异常

    为了保证程序的容错性与可靠性,即在遇到错误时有相应的处理机制不会任由程序崩溃掉,我们需要对异常进行处理 , 一般异常在项目中怎么处理呢? 写在日志中

    3.异常处理

    语法

    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子代码块,其余代码均正常运行

    当被检测的代码块中有可能触发不同类型的异常时,针对不同类型的异常:

    如果我们想分别用不同的逻辑处理,需要用到多分支的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时对应的处理逻辑
    

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

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

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

    语法

    try:    被检测的代码块except Exception:    其他类型的异常统一用此处的逻辑处理finally:    不处理异常,无论是否发生异常都会执行 finallyi的子代码    应该把被检测代码中回收系统资源的代码放到这里
    

    强行举例

    f=Nonetry:    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()
    

    4.什么时候使用异常处理

    在了解了异常处理机制后,本着提高程序容错性和可靠性的目的,读者可能会错误地认为应该尽可能多地为程序加上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 requestsfrom 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 resget('https://www.python.org')
    
  • 相关阅读:
    luogu P4284 [SHOI2014]概率充电器 期望 概率 树形dp
    luogu P5161 WD与数列 SAM 线段树合并 启发式合并
    5.5 省选模拟赛 B Permutation 构造 贪心
    luogu P3761 [TJOI2017]城市 树的直径 bfs
    一本通 1783 矩阵填数 状压dp 容斥 计数
    CF R638 div2 F Phoenix and Memory 贪心 线段树 构造 Hall定理
    BSOJ 5445 -- 【2018雅礼】树 prufer序列 dp
    CF1037H Security 线段树合并 SAM
    c++11の顺序容器
    c++11の关联容器
  • 原文地址:https://www.cnblogs.com/xcymn/p/15721360.html
Copyright © 2020-2023  润新知