Python异常处理

  • 什么是异常

异常 :异于常态就就异常。
简单来说就是我们的程序在运行过程中出错了。当我们的程序出现错误时,会把错误的原因、错误的位置、错误的种类输出到屏幕上

异常的组成

异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止),在python中,错误触发的异常如下这就是一个异常
Traceback叫做异常的追踪信息,我们可以通过它找到错误发生的位置
NameError叫做异常的种类,异常分为很多类,下面会介绍一些常见的异常
name ‘a’ is not defined 叫做异常的值,异常的值详细说明了这个地方为什么错了。

异常的分类

Python中,异常主要分为两大类:

  • 语法异常
    语法异常就是我们写的代码中出现了语法错误,这种异常会在python解释器检测语法时就抛出,这是我们最忌讳的,如果连正确的语法都写不好,那还怎么当一个程序员呢?
  • 逻辑异常
    检测语法时没有抛出语法异常,执行代码过程中抛出的异常就是逻辑异常。说的简单点就是我们的代码逻辑出现了漏洞,当代码执行到这个漏洞处时,掉进漏洞去了,这就是逻辑异常。

逻辑异常在没有运行代码前 是无法发现的
如果运行时,异常已经发生并且没有正确处理它
就抛出错误信息并且中断程序的执行

常见异常

AttributeError      试图访问一个对象没有的属性,比如foo.x,但是foo没有属性x
IOError             输入/输出异常;基本上是无法打开文件
ImportError         无法引入模块或包;基本上是路径问题或名称错误
IndentationError    缩进错误(语法错误的子类) ;代码没有正确对齐
IndexError          下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError            试图访问字典里不存在的键
KeyboardInterrupt   Ctrl+C被按下
NameError           使用一个还未被赋予对象的变量
SyntaxError         Python代码非法,代码不能编译(个人认为这就是语法错误)
TypeError           传入对象类型与要求的不符合
UnboundLocalError   试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它
ValueError          传入一个调用者不期望的值,即使值的类型是正确的
ZeroDivisionError   除数不能为0(栗子:5/0

  • 为什么要处理异常

我们写的程序不是给自己使用的,终归是要给用户使用的,如果用户每使用一会儿就抛出一个异常,那么还会有人使用我们写的程序吗?处理异常是为了使我们的程序更加稳定,不会轻易抛出异常终止程序。使用户有更好的体验感。


  • 怎么处理异常

第一种语法:

# try后面必须跟except,不然会抛出语法异常
try:
	# 可能出现异常的代码
	# 栗子:
	print(x)    # 我们打印一个还没有定义过的变量名,会抛出NameError
# except ‘上面代码可能出现的错误类型’:
# 栗子:
except NameError:
	# 当try中的代码体出现了异常其与except后面跟的错误类型匹配成功时执行
	# 栗子:上面抛出的异常是NameError时,才会执行这个except中的代码体
	print('名称还没有定义就使用了')

这里补充一下:

# try后面必须跟except,不然会抛出语法异常
try:
	# 可能出现异常的代码
	# 栗子:
	print(x)    # 我们打印一个还没有定义过的变量名,会抛出NameError
# except ‘上面代码可能出现的错误类型’:
# 栗子:
except NameError as e:
	# 当try中的代码体出现了异常其与except后面跟的错误类型匹配成功时执行
	# 栗子:上面抛出的异常是NameError时,才会执行这个except中的代码体
	print(e)
	# 可以将异常的值打印出来

我们说过,在python中,一切皆对象,异常也是对象,由异常类实例化产生,我们使用as语法获取这个异常对象,然后打印它;
前面我们学过打印一个对象时会触发类中的__str__方法。这里做的就是这样一件事

第二种语法:

# 注意:如果你知道一段代码一定会出错,应该做的是修改代码而不是用try去使程序能正常运行就ok
try:
	# 可能出现异常的代码
	# 栗子:
	x = 3 
	print(x)   # 这里x已经定义过,不会抛出异常
	li = [1,2,3]
	print(li[5])   # 这里
# except ‘上面代码可能出现的错误类型’:
# except可以连用
# 栗子:
except NameError:    
	# 当try中的代码体出现了异常其与except后面跟的错误类型匹配成功时执行
	# 栗子:上面抛出的异常是NameError时,才会执行这个except中的代码体
	print('名称还没有定义就使用了')
except IndexError:
	# 当try中的代码体出现了异常其与except后面跟的错误类型匹配成功时执行
	# 栗子:上面抛出的异常是IndexError时,才会执行这个except中的代码体
	print('超出列表索引值范围')
# except连用可以写多个,可以将可能出现的异常全部捕获,
# 这里需要注意一点:当try中的代码体中间出现了异常,就会直接跳到下面来执行except代码去匹配,如果抛出的异常没有被except,就会输出到屏幕,如果被except,就会执行相应的except下的代码。

第三种语法:

try:
	# 可能出现异常的代码
	print(x)
	li = [1,2,3]
	print(li[5])
except (NameError, IndexError):
	# 当try中的代码体出现了异常其与except后面跟的错误类型匹配成功时执行
	# 栗子:上面抛出的异常是NameError或IndexError时,才会执行这个except中的代码体
	print('这里出现了错误')

第四种语法:
通过上面的例子想必大家都已经能明白try的基本使用规则了,那么下面的例子会更简便的写。

try:
	可能出现异常代码
except Exception:
	# 万能异常,就是可以捕获所有的异常类型,只要上面抛出了异常,这里就可以捕捉到
	print('出错了')

第五种语法:

try:
	可能出现异常的代码
except 可能出现的异常类型:
	与try中抛出的异常匹配成功时执行的代码
else:
	当try中没有抛出异常时执行这部分代码体

else的用法很简单,就是在try的代码体中没有抛出任何异常时会执行。
第六种语法:

try:
	可能出现异常的代码
except 可能出现的异常类型:
	与try中抛出的异常匹配成功时执行的代码
finally:
	不管上面的执行情况如何都会执行的代码体
'''
例子:
try:
    f = open("a.txt(假设这个文件时存在的)","rt",encoding="utf-8")
    f.read()   # 我们以读的方式打开文件
    f.write("123")   # 写入时肯定会抛出异常
    f.close()    # 这里是为了演示使用方法才主动写bug的,平时try中应该放一些不确定会不会出现异常的代码
except Exception:
    print("发生异常了")
finally:
    print("关闭文件!")
    f.close()
'''

finally语法也很简单,不管finally上面的代码如何执行都会执行finally代码体
else还可以和finally连用,连用时必须保证finally语句在所有except,else的下面

主动抛出异常

在python中,我们可以使用raise语句主动抛出一个异常
当我们的程序执行时,我们已经明确说明这件事不应该这么做,用户还要这么做的时候,我们就应该主动抛出异常时程序终止。

raise NameError
# raise后面必须跟一个异常的类型,可以是python自带的异常类型,也可以是我们自己定义的异常类型,接下来我们就介绍一下如何自定义一个异常

自定义异常

'''
当系统提供的这些异常类型 和你要描述的错误不匹配时 就需要自定义异常类型
写法:
    class 自定义异常类型名称(BaseException):
总结:之所以自定义异常类型 是为了更具体描述你的错误 让使用者一眼就看出了
'''
class UnlikeError(BaseException):
    def __init__(self,msg,text):
        self.msg = msg
        self.text = text
    def __str__(self):
    	print(self.msg)
# 这样我们就自定义了一个异常,还定义了打印这个异常类的对象时输出的信息
# 自定义异常只能通过raise语句来抛出

断言

今天的最后一个知识点了,耐住心思看完吧。
assert语句

'''
断言: 可以理解为断定  就是很清楚,很明确的意思
什么时候需要断言?
    下面的代码必须依赖上面代码的正确数据才能执行时
语法: assert 后面跟结果为Bool的表达式
    如果值为True 则继续往下执行
    为False 抛出一个 AssertionError 表示断言失败
没有assert 也可以使用if来写判断 assert 仅仅是简化了代码
'''
# 第一部分代码 负责产生一个列表
li = []
# li.append(1)
# li.append(2)
# 这里一定要确保数据是有效的
# if len(li) < 1:
#     raise ValueError("列表中没有数据!")
assert len(li) > 0
# 需要使用列表中的数据来完成任务 如果没有数据无法完成
print(li[0])
print(li[1])

最后

真的是最后了:

有的同学会这么想,学完了异常处理后,好强大,我要为我的每一段程序都加上try…except,干毛线去思考它会不会有逻辑错误啊,这样就很好啊,多省脑细胞===》2B青年欢乐多
首先try…except是你附加给你的程序的一种异常处理的逻辑,与你的主要的工作是没有关系的,这种东西加的多了,会导致你的代码可读性变差
然后异常处理本就不是你2b逻辑的擦屁股纸,只有在错误发生的条件无法预知的情况下,才应该加上try…except

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Noah Ren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值