异常处理
一:元类补充
__new__与__init__的区别:
__new与__init__先执行,其作用是创建一个空的对象,作为一个类的对象,必须具备三个组成部分,所以调用type中的__new__来完成组装,得到这个类对象后需要将其返回,以供__init__来使用。
class MyMeta(type): # 用于新建类对象 def __new__(cls, *args, **kwargs): print("new run") # print(MyMeta) # print(*args) # 调用type通过的__new__方法来创建一个空的类对象 已经将三个组成部分都放到类对象中了 res = type.__new__(cls,*args) return res def __init__(self,class_name,bases,namespace): print("init run") print(self) class Student(metaclass=MyMeta): pass print(Student)
二:异常处理
1:什么是异常?
异常指的就是程序运行时发生的错误(在程序出现错误时,则会产生下一个异常,如果程序没有处理它,则会抛出该异常,代码也就不再继续运行下去了)。在python中,错误触发的异常有多种,示例如下:
错误分为两种:一种是语法错误(这种错误根本过不了python解释器的语法检测,必须在程序执行前就改正),另一种就是逻辑错误。
#TypeError:int类型不可迭代 for i in 3: pass #ValueError num=input(">>: ") #输入hello int(num) #NameError aaa #IndexError l=['egon','aa'] l[3] #KeyError dic={'name':'egon'} dic['age'] #AttributeError class Foo:pass Foo.x f = open("1.今日内容") f.close() f.read() #ValueError: I/O operation on closed file. 文件已经关闭 你还要去读写 def func(): print(1) print(2) # IndentationError: unexpected indent 缩进错误 #ZeroDivisionError:无法完成计算 res1=1/0 res2=1+'str'
2.异常的种类
在python中不同的异常可以用不同的类型(python中统一了类与类型,类即类型)去标识,一个异常标识一种错误。
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入模块或包;基本上是路径问题或名称错误 IndentationError 语法错误(的子类) ;代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了) TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
3.异常处理
3.1如果错误的发生条件是可预知的,我们需要进行if进行处理,在错误发生之前进行预防。
AGE=10 while True: age=input('>>: ').strip() if age.isdigit(): #只有在age为字符串形式的整数时,下列代码才不会出错,该条件是可预知的 age=int(age) if age == AGE: print('you got it') break
3.2如果错误的发生条件是不可预知的,则需要用到try...except:在错误发生之后进行处理。
基本语法为: try: 被检测的代码块 except 异常类型: try中一旦检测到异常,就执行这个位置的逻辑 例如: try: print('beginning') a=int('abc') print('error') except ValueError: print('发生了ValueError异常') print('over') ======================================= >>>: beginning 发生了ValueError异常 over
# 语法1 try: # 把可能发出错误的代码放到try中 print("start") # a = int("abc") li[1] print("over") except ValueError: # 当try中真的发生了错误 就会执行 except中的代码 # 在这里可以做一些补救措施 print("发生了 ValueError异常") print("over")
# 语法2 except可以有多个 try: # 把可能发出错误的代码放到try中 print("start") a = int("abc") li[1] print("over") except ValueError: # 当try中真的发生了错误 就会执行 except中的代码 # 在这里可以做一些补救措施 print("发生了 ValueError异常") except IndexError: print("发生了 IndexError 索引不正确") print("over")
语法3 万能异常 Exception类 尽量少用 可能会导致 程序既不报错 也不正常运行 无法定位错误位置 # try: # # 把可能发出错误的代码放到try中 # print("start") # # a = int("abc") # # li[1] # dic = {} # dic["name"] # print("over") # # except Exception: # print("可能是任何类型的错误 反正是发生错误了") # print("over") #但是具体不知道是发生了什么错误,尽量少用,可能会导致程序既不报错,也不正常运行,无法定位错误位置。
语法4 万能异常 Exception类 建议 输出异常的值 # try: # # 把可能发出错误的代码放到try中 # print("start") # # a = int("abc") # # li[1] # dic = {} # dic["name"] # print("over") # # # 可以通过给异常取别名 来获取异常的对象 对象中包含了错误信息 # except Exception as e: # print("可能是任何类型的错误 反正是发生错误了") # print(e) # print(type(e)) # print("over") #建议将异常类型打印出来
# 语法5 先捕获能够明确的异常类型 最后捕获万能异常类型 try: # 把可能发出错误的代码放到try中 print("start") # a = int("abc") # li[1] # 10 / 0 dic = {} dic["name"] print("over") except ValueError: print("值不对.....") except ZeroDivisionError: print("除数不能为0") # 可以通过给异常取别名 来获取异常的对象 对象中包含了错误信息 except Exception as e: print("可能是任何类型的错误 反正是发生错误了") print(e) print(type(e)) print("over") #建议将万能异常放在最后执行,等其他异常执行完之后没有捕捉到异常才会执行万能异常。
# 语法6 try except else try: # 把可能发出错误的代码放到try中 print("start") # a = int("abc") # li[1] # 10 / 0 dic = {} # dic["name"] print("over") except ValueError: print("值不对.....") except ZeroDivisionError: print("除数不能为0") # 可以通过给异常取别名 来获取异常的对象 对象中包含了错误信息 except Exception as e: print("可能是任何类型的错误 反正是发生错误了") print(e) print(type(e)) else: #当没有发生异常会执行else 只能except的后面 print("执行了else") print("over")
# 语法7 try except finally try: # 把可能发出错误的代码放到try中 print("start") # a = int("abc") # li[1] # 10 / 0 dic = {} # dic["name"] print("over") except ValueError: print("值不对.....") finally: #无论是否发生异常 最后都会执行finally中的代码 print("finally") print("over")
import io # finally的使用场景 可以用finally来执行一些清理操作 类似__del__ try: print("start") f = open("1.今日内容","rt",encoding="utf-8") f.read() print("end") except FileNotFoundError: print("文件路径错误...") except io.UnsupportedOperation: print("文件不能被写入....") finally: f.close() print(f.closed)
""" 做一个登录功能 如果登录失败就抛异常 """ # 主动抛出异常 # 当你写了一些功能 是提供给别人用的 然而使用者不按照你的方式来使用,就会导致程序出错 # 而且我们无法帮助用户处理这个错误 # 这时候就可以主动抛出异常 # raise 关键字 后面跟 任意Exception类型的子类 # 自定义异常类型 class LoginException(Exception): pass def login(): name = input("username:").strip() pwd = input("password:").strip() if name == "Grace" and pwd == "123": print("登录成功!") else: raise LoginException("用户名或密码不正确....") login()
4.断言
断言就是很确定某个条件一定成立(有一段代码,要执行就必须要保证某个条件是成立的)。使用断言来简化代码,断言后面跟一个bool类型表达式,如果为True则继续往下执行,否则抛出异常,其局限性是:异常类型是固定的,而且不能指定异常信息。
#断言条件 #assert 1==1 (true) #assert 1==2 (false) names = ["张三","李四","王麻子"] names=[] assert 1 print('正在处理数据') print('正在处理数据') print('正在处理数据') print('正在处理数据') print('正在处理数据') print('正在处理数据')