异常与异常捕获

异常与异常捕获

异常

异常以及异常类型

异常就是代码运行报错,行业俗语叫bug。
代码运行中一旦遇到异常会直接结束整个程序的运行,我们在编写代码的过程中药尽可能避免。

代码报错有两种:

  • 语法错误

    语法错误是明眼人一眼能够看出来的,语法这是程序员的基础技能,不容有错

  • 逻辑错误

    一眼可能看不出来,需要经验积累能感知到可能有的逻辑错误。

    比方说,上文变量经过分支可能被赋值为一个字符串类型的数据,但是在后面执行了一个列表的内置方法报错了。

异常信息

python中会执行遇到异常时抛出异常信息,通常包含三个内容

  • 异常位置
  • 异常类型
  • 异常详情

img

常见异常类型

SyntaxError|NameError|IndexError|KeyError|IndentationError等等

异常捕获

基础语法结构

我们在执行程序中,有一些语句可能无法预料是否异常,这时就要使用关键字tryexcept来捕获这里的异常。防止程序异常后直接报错而不往后执行了。

try:
	一段可能报错的程序
except 异常类型:
    print('你这段代码中遇到了异常')

白话文来解释这段程序:尝试一段可能报错的程序,如果产生了except后的异常类型,那么这段程序停止后不会报出异常信息(异常被捕获了),转而执行except关键字下的子代码块。

来看一个例子:

try:
    name  # name没有被定义,所以这里引用会异常
    print('aaa')  # 上面遇到异常后,后续的程序不会执行
except NameError:  # 捕捉名称错误的异常
    print('出现名称异常')
    
## 运行结果
出现名称异常

image

其他语法结构

  1. 查看系统提示的异常信息

    try:
        name
    except NameError as e:  # 我们通常用变量e来存储错误信息
        print(e)  # name 'name' is not defined
    

    as充当赋值符号,将捕获到的异常,传值给e

  2. 针对不同的异常类型制定不同的方案

    try:
        l1 = [11,22,3,4]
        l1[5]
        name
        d1 = {'name':'leethon'}
        d1['age']
    except NameError as e:  
        print('名称异常了')  # 如果最早遇到名称异常,则执行此代码
    except IndexError as e: 
        print('索引异常了,异常信息是:', e)   # 如果最早遇到索引异常,则执行此代码
    except KeyError as e:
        print('关键字异常了')  # 如果最早遇到关键字异常,则执行此代码
    

    可以多写几个except来捕获不同的异常类型,分别执行不同的策略来应对这种异常。

  3. 万能异常 Exception/BaseException

    try:
        l1 = [11,22,3,4]
        l1[5]
        name
        d1 = {'name':'leethon'}
        d1['age']
    except Exception as e:  # 无论什么异常都能捕捉
        print(e)  # 无论什么异常都执行同样的代码
    
  4. 结合else使用(了解)

    try:
        # 这是一套可能出错的程序,但是没有出错
        pass
    except Exception as e:
        print(e)
    else:
        print('我哪错了(噘嘴)')
        
    ## 执行结果
    我哪错了(噘嘴)
    

    当尝试执行的代码没有出现任何问题时,则会执行else下的子代码块。

  5. 结合finally使用

    try:
        f = open('a.txt', 'r', encoding='utf8')
        ff.read()  # 这里可能出错了
        f.close()
    except Exception as e:  # 捕捉异常
        print(e)  # 打印错误信息
    else:
        print('我哪错了(噘嘴)')
    finally:
        f.close()  # 无论是否捕捉到异常都会执行。
        print('我来兜底,解救你的内存')
    

    无论尝试执行的代码是否异常都会执行finally下的子代码,此句可以防止一些需要上下文联系的代码在中间出错时,后续的代码没能执行的情况。

关键字补充(了解)

  • 断言 —— assert

    assert 条件
    后续代码
    

    如果assert后续的条件为真,则正常执行后续代码,不然就抛出异常。

    name = 'leethon'
    assert name == 'lee'  # 后面这个条件判定为假,报错AssertionError
    print('没错是我')  # 没有执行
    
  • 主动抛异常 —— raise

    name = 'god'
    if name != 'leethon':
        raise NameError('爷要罢工')  # 运行到这里,抛出异常,异常类型和信息可以自己指定
    print('社畜,继续去工作吧')
    
    # 运行结果
    NameError: 爷要罢工
    

异常处理应用场景

异常处理虽然可以防止我们的程序报错,但应该尽量少用,因为它该中断还是中断,会影响我们的功能实现,应做到:

  • 使用try的次数尽量少
  • 一个try下的代码尽量短

try一般用于真的拿不准的时候才会用,一定会报错的程序应该修改,一定不会报错的程序也不该占用监测资源,如:我们在突然断网时会抛出网络异常,这种异常是无法预料的。

try实战小题

结合迭代器的相关知识,实现for循环遍历列表打印

l1 = [111, 222, 333, 444, 555]
ite = l1.__iter__()
try:
    while True:
        print(ite.__next__())
except StopIteration:
    pass
posted @ 2022-10-17 17:25  leethon  阅读(55)  评论(0编辑  收藏  举报