异常处理
一、什么是异常
异常是错误发生前的一种信号,如果没有人来处理这个信, 程序就会中断执行并抛出错误信息。
二、异常的分类
1.语法检查异常
2.运行时异常(逻辑异常)
这种异常只有在代码被执行时才能发现
特点:在没有运行代码前 是无法发现的
如果运行时异常已经发生并且没有正确处理他 就抛出错误信息
并且中断程序的执行。
三、异常的组成
1.追踪信息 (具体发生异常的位置 以及函数的调用顺序)
2.异常的类型 (错误的类型)
3.异常的消息 (详细的错误信息)
学习异常处理的目的:为了让我们的程序更加稳定 (健壮性) 不容易崩溃
name = def func(): import xxaaa def func1(): func() func1()
File "C:/Users/xxx/PycharmProjects/MyFirstPro/chapter5-面向对象//异常处理.py", line 32 name = ^ SyntaxError: invalid syntax
四、常见的异常
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入模块或包;基本上是路径问题或名称错误 IndentationError 语法错误(的子类) ;代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了) TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
五、异常处理
如果错误发生的条件是不可预知的,则需要用到try…except:在错误发生之后进行处理。
常用基本语法:
try: 这里放可能出现异常的代码 except: 异常的类型: 当异常发生并且异常类型匹配时 执行except中的代码 注意:一旦try中有代码抛出了异常 后面的代码全都不执行
# print("staring.....") # try: # name # except NameError: # print("名字找不到!") # print("end.......")
#多种异常类型处理 # print("staring.....") # try: # name # [][-1] # pass # except NameError: # print("名字找不到!") # except IndexError: # print("索引超出范围") # print("end.......")
当代码可能出现多种异常时的写法时:(两种写法)
# print("staring.....") # try: # # name # # [][-1] # 1/0 # pass # except NameError: # print("名字找不到!") # except IndexError: # print("索引超出范围") # except ZeroDivisionError: # print("除数不能为0") # print("end.......")
# print("staring.....") # try: # {}["aaa"] # # name # # [][-1] # 1/0 # except (NameError,IndexError,ZeroDivisionError): # print("可能名字找不到! 可能所以超出范围 可能除数为0") # print("end.......") # 上面两种写法 都可以处理多种异常 但是 异常类型太多了 不可能全写完
注意:万能异常类型 Exception 或BaseException 基于OOP的继承和多态
再例举几种不太常用的语法:
语法1 try: except: else: try中没有发生异常时执行 语法2 try : except : finally : 无论是否发生异常 都会执行finally 可以用来回收系统资源!
# print("start...") # try: # # 1/0 # [][1] # pass # except ZeroDivisionError: # print("除数异常") # except NameError: # print("名字异常") # else: # print("else会在 try中没有异常时执行") # print("end...")
finally # print("start...") # try: # # 1/0 # # [][1] # pass # except ZeroDivisionError: # print("除数异常") # except IndexError: # print("索引异常") # else: # print("else会在 try中没有异常时执行") # finally: # print("finally 无论异常是否发生 都会执行!") # print("end...")
# 使用finally来回收资源 try: f = open(r"D:\上海python全栈4期\day31\异常处理\1今日内容","rt",encoding="utf-8") f.read() # f.write("123") except Exception: print("发生异常了") finally: print("关闭文件!") f.close() print(f.closed)
主动抛出异常:
""" 当程序中有一些限制 然而用户没有遵守 我们可以主动抛出异常 语法: raise 异常类型(异常的详细信息) 类型必须是BaseException的子类 """ # raise NameError("这就是名字不存在异常!") age = input("请输入整型的年龄:") if not age.isdigit(): raise TypeError("你输入的不是整型!") age = int(age) print("十年后你%s岁" % (age + 10))
断言:(断定 就是很清楚 很明确)
啥时候用? 下面的代码必须依赖上面代码的正确数据
语法: 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[0]) print(li[0]) print(li[0])
自定义异常类型
当系统提供的这些异常类型 和你要描述的错误不匹配时 就需要自定义异常类型
写法:
class 自定义异常类型名称(BaseException):
总结一下:之所以自定义异常类型 是为了更具体描述你的错误 让使用者一眼就看出了
关键点:
1.如何自定义异常类型
2.在except中 使用as 来获取异常对象
class UnlikeError(BaseException): def __init__(self,msg,text): self.msg = msg self.text = text # 函数中可能抛出异常 def hello(): text = input("输入一段话:") if text == "你真帅": print("你说得对!") else: raise UnlikeError("你再看看...","另一个参数") # 捕获异常 try: hello() # 获取异常对象 except UnlikeError as e: print(e.text)
conclusion:
不应该滥用try except
什么时候用? 如果你知道为什么出错 应该把代码修改正确 而不是加上try except,寻找代码根本错误问题是关键!
你不清楚为什么会发生异常! 这时候可以用。
try: f = open("xxxx","rt") f.read() except Exception: print("文件不存在!")