当前位置: 首页 > news >正文

Python基础之异常处理

程序在运行过程中,难免会遇到错误,有的是编写人员疏忽造成的语法错误,有的是程序内部隐含逻辑问题造成的数据错误,还有的是程序运行时与系统的规则冲突造成的系统错误,等等。如果出错就不会执行出错语句后面的代码,导致程序异常中断,因此为了提高程序健壮性,容错性,对容易发生错误的语句需要捕获异常对异常处理,保证程序的连续性提高稳定性。

def get_num(l:list, n1:int, n2:int):print('执行get_num函数')num1 = l[n1]num2 = l[n2]res = num1/num2return resdef func_1():print('执行func_1函数')def func_2():print('执行func_2函数')get_num([1,2,3,4],5)
func_1()
func_2()

上述代码在调用函数get_num时会抛出indexError的异常,导致程序中断 

def func_1():x = 10y = 0b = x/yprint(b)print("做完除法后需要执行的代码")Traceback (most recent call last):File "/Users/fujinjie/PythonProjects/develop_test/buyer_app_autotest/unit_test.py", line 30, in <module>r = func_1()File "/Users/fujinjie/PythonProjects/develop_test/buyer_app_autotest/unit_test.py", line 26, in func_1b = x/y
ZeroDivisionError: division by zero

由于y = 0 ,即除数为0,程序抛出:ZeroDivisionError: division by zero 的异常,b = x/y后面的代码并没有被继续执行,因为出错后程序是并不知道如何处理所以直接中断后续,并抛出错误告知用户,假设在我们自动化测试中,可能要执数百条用例,如果某一句子代码执行出现异常,则自动化程序就会异常中断无法继续执行测试。

当一个程序发生异常时,代表该程序在执行时出现了非正常的情况,无法再执行下去。默认情况下,程序是要终止的。如果要避免程序退出,可以使用捕获异常的方式获取这个异常的名称,再通过其他的逻辑代码让程序继续运行,这种根据异常做出的逻辑处理叫作异常处理。异常处理不仅仅能够管理正常的流程运行,还能够在程序出错时对程序进行必要的处理。大大提高了程序的健壮性和人机交互的友好性。

一、try...except...异常处理机制

def func_1():x = 10y = 0try:b = x/yprint(b)except:  # except捕获所有类型的异常,即只要有异常就捕获,不区分异常类型print("出现错误异常后,执行这里")print("做完除法后需要执行的代码")#出现错误异常后,执行这里做完除法后需要执行的代码

上面是通过try...except 优化后的函数,把会出错的代码放入try: 语句下作为try的子句,当try下面的代码出错时,程序会执行except:下面的代码,并执行程序后续代码,如果try: 下面的代码没有出错,则跳过except: 直接执行后续代码,程序继续运行。

在这里通过except我们捕获try代码块中的错误和异常,相当于告诉程序,当try下面语句出错时,该如何处理,上面我们直接做了一个字符串的输出: "出现错误异常后,执行这里"

二、except + 异常类型 捕获指定类型的异常

def func_1():x = 10y = 0try:b = x/yprint(b)except ZeroDivisionError as e:  # as 为别名,当一个变量名称太长时可取别名代替简化print(f"出错啦,错误信息:{e}")print("做完除法后需要执行的代码")出错啦,错误信息:division by zero
做完除法后需要执行的代码

基本语法构成

try:可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:处理异常的代码块1
except [ (Error3, Error4, ... ) [as e] ]:处理异常的代码块2
except [Exception]:处理其它异常

该格式中,[] 括起来的部分可以使用,也可以省略。其中各部分的含义如下:

  • (Error1, Error2,...) 、(Error3, Error4,...):其中,Error1、Error2、Error3 和 Error4 都是具体的异常类型。显然,一个 except 块可以同时处理多种异常。
  • [as e]:作为可选参数,表示给异常类型起一个别名 e,这样做的好处是方便在 except 块中调用异常类型(后续会用到)。
  • [Exception]:作为可选参数,可以代指程序可能发生的所有异常情况,其通常用在最后一个 except 块。

try except 语句的执行流程如下:

  1. 首先执行 try 中的代码块,如果执行过程中出现异常,系统会自动生成一个异常类型,并将该异常提交给 Python 解释器,此过程称为。

    捕获异常

  2. 当 Python 解释器收到异常对象时,会寻找能处理该异常对象的 except 块,如果找到合适的 except 块,则把该异常对象交给该 except 块处理,这个过程被称为处理异常。如果 Python 解释器找不到处理异常的 except 块,则程序运行终止,Python 解释器也将退出。

很多时间我们并不知道try下面包裹的子句会出现何种类型的异常,对于这种情况我们一般交给 Exception来处理,即表示可以接收任何类型的异常

 

try:#...
except Exception:#...

一个简的例子

try:num_1 = int(input("输入一个整数:"))num_2 = int(input("输入另一个整数:"))print( num_1/num_2 )
except ValueError:print("数值错误:程序只能接收整数参数")
except ArithmeticError:print("算术错误")
except Exception:print("未知异常")

该程序中,根据用户输入num_1 和 num_2 值的不同,可能会导致 ValueError、ArithmeticError 异常:

  1. 如果用户输入的 num_1 或者 num_2 是其他字符,而不是数字,会发生 ValueError 异常,try 块会捕获到该类型异常,同时 Python 解释器会调用第一个 except 块处理异常;
  2. 如果用户输入的 num_1 和 num_2 是数字,但 num_2 的值为 0,由于在进行除法运算时除数不能为 0,因此会发生 ArithmeticError 异常,try 块会捕获该异常,同时 Python 解释器会调用第二个 except 块处理异常;
  3. 当然,程序运行过程中,还可能由于其他因素出现异常,try 块都可以捕获,同时 Python 会调用最后一个 except 块来处理。

通过traceback.format_exc()返回异常栈(返回是数据类型是字符串)

 

import tracebackdef func_1():x = 10y = 0try:b = x/yprint(b)except ZeroDivisionError as e: # as 为别名,当一个变量名称太长时可取别名代替简化ei = traceback.format_exc()print(f"出错啦,错误信息:{e},{ei}")print("做完除法后需要执行的代码")出错啦,错误信息:division by zero,Traceback (most recent call last):File "C:\Users\37210\Desktop\Jcmall_study\test_b\b_3.py", line 8, in func_1b = x/y
ZeroDivisionError: division by zero做完除法后需要执行的代码

 常见异常举例

IOError 输入/输出异常;基本上是无法打开文件
TypeError 传入对象类型与要求的不符合
AttributeError 无法访问该对象,一般对象不存在,比如foo.x,但是foo没有属性x
ImportError  无法引入模块或包;基本上是路径问题或名称错误
IndentationError  语法错误(的子类) ;代码没有正确对齐
IndexError  下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError  试图访问字典里不存在的键
NameError  使用一个还未被赋予对象的变量
SyntaxError Python代码非法,一般是语法错误

except 后面可以指定捕获的错误类型,错误类型指定后,如果try:下面的代码抛出的错误类型非该指定的类型,则不会被捕获,程序仍旧会异常终止; 

 

def func_1():x = 10y = 0try:b = x/yprint(b)except ValueError as e:  # 这里对ValueError的异常进行捕获print(f"出错啦,错误信息:{e}")print("做完除法后需要执行的代码")Traceback (most recent call last):File "/Users/fujinjie/PythonProjects/develop_test/buyer_app_autotest/unit_test.py", line 33, in <module>r = func_1()File "/Users/fujinjie/PythonProjects/develop_test/buyer_app_autotest/unit_test.py", line 27, in func_1b = x/y
ZeroDivisionError: division by zero

三、except 捕获多个指定的错误类型 

def func_1():x = 10y = 0try:b = x/yprint(b)except (TypeError,ValueError,ZeroDivisionError) as e:  # 这里对									  ZeroDivisionError的异常进行捕获print(f"出错啦,错误信息:{e}")print("做完除法后需要执行的代码")出错啦,错误信息:division by zero
做完除法后需要执行的代码def func_1():x = 10y = "0"    # 此处y是一个str类型try:b = x/yprint(b)except (TypeError,ValueError,ZeroDivisionError) as e:  # 这里对												TypeError的异常进行捕获print(f"出错啦,错误信息:{e}")print("做完除法后需要执行的代码")出错啦,错误信息:unsupported operand type(s) for /: 'int' and 'str'
做完除法后需要执行的代码

四、try...except...finally

Python异常处理机制还提供了一个 finally 语句,通常用来为 try 块中的程序做扫尾清理工作

注意:finally 只要求和 try 搭配使用,而至于该结构中是否包含 except ,对于 finally 不是必须的

finally 语句的功能是:无论 try 块是否发生异常,最终都要进入 finally 语句,并执行其中的代码块。

def func_1():x = 10y = 0try:b = x/yprint(b)finally:print("无论try中代码是不出现异常,finally中代码始终会被执行")print("继续执行模块中其他代码")def func_2():x = 10y = 1try:b = x/yprint(b)finally:print("无论try中代码是不出现异常,finally中代码始终会被执行")print("继续执行模块中其他代码")

比较上面两个函数 func_1与func_2,func_1中的try代码块会出现异常,func_2中的try代码块未出现异常,但两个函数的finally包裹的子句都得到了执行

五、try...except...else

在原本的

try except

结构的基础上,Python异常处理机制还提供了一个 else 块,也就是原有 try except 语句的基础上再添加一个 else 块,即

try:#...
except:#...
else:#...

使用 else 包裹的代码,只有当 try 块没有捕获到任何异常时,才会得到执行;反之,如果 try 块捕获到异常,即便调用对应的 except 处理完异常,else 块中的代码也不会得到执行。

注意:else 必须和 try except 搭配使用

 

try:result = 20 / int(input('请输入除数:'))print(result)
except ValueError:print('必须输入整数')
except ArithmeticError:print('算术错误,除数不能为 0')
else:print('没有出现异常')
print("继续执行")

try: 下面的代码未发生异常,则执行else: 下面的代码,如果发生异常则执行except: 下面的代码,因此esle: 代码块的执行与否,取决于try: 是否报异常; 

def func_1():x = 10y = 1try:b = x/yprint(b)except:  # except捕获所有类型的异常,即只要有异常就捕获,不区分异常类型print("出现错误异常后,执行这里")else:print("没有异常会执行这里的代码")finally:print("finally中代码始终会被执行")print("做完除法后需要执行的代码")

总结一个

Python异常处理语法结构如下

try:#业务实现代码
except Exception1 as e:#捕获到Exception1异常后执行此代码...
except Exception2 as e:#捕获到Exception2异常后执行此代码...
#可以有多个 except
...
else:#try中未出现异常是执行此处代码,有异常时不会执行
finally :#不管try中代码是否出现异常,此处代码始终会执行...

注:finally必须跟try连用,跟except与else无连用关系;else必须跟try...except...连用

即整个结构try是必须存在的

  • 如果没有 try 块,则不能有后面的 except 块、else 块和 finally 块。但是也不能只使用 try 块,要么使用 try except 结构,要么使用 try finally 结构;
  • except 块、else 块、finally 块都是可选的,当然也可以同时出现;
  • 可以有多个 except 块,多个 except 块必须位于 try 块之后,finally 块必须位于所有的 except 块之后。
  • 要使用 else 块,其前面必须包含 try 和 except。

异常处理执行过程

 

练习:

1、下面代码存在keyError异常,请通过try...except捕获并处理该异常,当错误时print输出“输入的key不存在,请检查key”

goods_inf = {'Id': 10001, 'goods': 'JBL小音响', 'price': 501}
def get_goods_inf(goods:dict, key:str):res = goods[key]return resget_goods_inf(goods=goods_inf, key='id')

2、请优化下面函数,当除数为0时捕获异常并告知用户除数不能为0,当输入的是非数字时捕获异常并提示用户输入的是非数字字符 

def add_num():num1 = int(input('请输入被除数:'))num2 = int(input('请输入除数:'))res = num1/num2return res

 

3、基于add_num函数,请通过try...except...else优化,当未捕获到异常是函数返回res,当捕获到异常时函数一律返回”输入错误,请检查输入并把这个异常类型打印出来“

4、基于add_num函数,请通过finally进行优化,函数始终会通过print输出’add_num函数执行完毕’

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关文章:

  • springboot配置项动态刷新
  • 应用层—HTTPS详解(对称加密、非对称加密、密钥……)
  • 5G_系统同步机制(八)
  • JVM篇--垃圾回收器高频面试题
  • R语言【cli】——ansi_trimws():从ANSI字符串中删除前导和/或尾随空格
  • 链表|数据结构|C语言深入学习
  • c++设计模式之单例模式
  • 力扣(leetcode)第35题搜索插入位置(Python)
  • Git 操作
  • 启动低轨道卫星LEO通讯产业与6G 3GPP NTN标准
  • 纯前端网页编辑Office文档安全预览之打开Word文档后禁止另存为....
  • P1068 [NOIP2009 普及组] 分数线划定————C++、Python
  • HTML+CSS:飞翔按钮
  • 04 单链表
  • Go 爬虫之 colly 从入门到不放弃指南
  • hexo+github搭建个人博客
  • Codepen 每日精选(2018-3-25)
  • conda常用的命令
  • JavaScript设计模式与开发实践系列之策略模式
  • Linux链接文件
  • ng6--错误信息小结(持续更新)
  • PHP变量
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • ReactNative开发常用的三方模块
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • Vue 动态创建 component
  • Vue.js源码(2):初探List Rendering
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​​​​​​​​​​​​​​Γ函数
  • ​Java并发新构件之Exchanger
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (145)光线追踪距离场柔和阴影
  • (C++17) std算法之执行策略 execution
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (未解决)macOS matplotlib 中文是方框
  • (一)SpringBoot3---尚硅谷总结
  • .jks文件(JAVA KeyStore)
  • .net core使用ef 6
  • .net 受管制代码
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .NET/MSBuild 中的发布路径在哪里呢?如何在扩展编译的时候修改发布路径中的文件呢?
  • .skip() 和 .only() 的使用
  • @Bean注解详解
  • @TableId注解详细介绍 mybaits 实体类主键注解
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • [ 常用工具篇 ] AntSword 蚁剑安装及使用详解
  • [2021ICPC济南 L] Strange Series (Bell 数 多项式exp)