day27:异常&反射
目录
3.AssertionError(断言assert语句失败)
3.try ... except ... else ... finally ...
认识异常处理
1.程序错误的种类
程序错误分为两种:语法错误 和 异常错误
1.语法错误:代码没有按照python规定语法去写,发明创造产生的错误
2.异常错误:在代码语法正确的前提下,程序报错就是异常
2.异常的分类
# IndexError 索引超出序列的范围 # KeyError 字典中查找一个不存在的关键字 # NameError 尝试访问一个不存在的变量 # IndentationError 缩进错误 # AttributeError 尝试访问未知的对象属性 # StopIteration 迭代器没有更多的值 # AssertionError 断言语句(assert)失败 # EOFError 用户输入文件末尾标志EOF(Ctrl+d) # FloatingPointError 浮点计算错误 # GeneratorExit generator.close()方法被调用的时候 # ImportError 导入模块失败的时候 # KeyboardInterrupt 用户输入中断键(Ctrl+c) # MemoryError 内存溢出(可通过删除对象释放内存) # NotImplementedError 尚未实现的方法 # OSError 操作系统产生的异常(例如打开一个不存在的文件) # OverflowError 数值运算超出最大限制 # ReferenceError 弱引用(weak reference)试图访问一个已经被垃圾回收机制回收了的对象 # RuntimeError 一般的运行时错误 # SyntaxError Python的语法错误 # TabError Tab和空格混合使用 # SystemError Python编译器系统错误 # SystemExit Python编译器进程被关闭 # TypeError 不同类型间的无效操作 # UnboundLocalError 访问一个未初始化的本地变量(NameError的子类) # UnicodeError Unicode相关的错误(ValueError的子类) # UnicodeEncodeError Unicode编码时的错误(UnicodeError的子类) # UnicodeDecodeError Unicode解码时的错误(UnicodeError的子类) # UnicodeTranslateError Unicode转换时的错误(UnicodeError的子类) # ValueError 传入无效的参数 # ZeroDivisionError 除数为零
3.AssertionError(断言assert语句失败)
什么是断言?
断言就是猜的意思
assert 和 if 之间的区别在于
assert 在断言失败时候,是直接报错,抛出异常,后面的代码直接终止了
if 在判断为False 的时候,不执行代码
assert 3>1 assert 3>1000 print("ok")
异常处理的基本语法
1.异常处理的基本语法
try ... except ...
把有问题的代码放到try这个代码块当中
如果出现了异常,会直接执行except这个代码块中的内容
作用:防止异常抛错,终止程序.
try : lst = [1,2,3] print(lst[90]) except: print("这里有异常错误~")
2.带有分支的异常处理
在说这个之前,先说一个语法:
except + 异常错误类:特指发生在这类异常错误时,要执行的分支
try: # IndexError # lst = [1,2,3] # print(lst[90]) # KeyError # dic = {} # print(dic["a"]) # NameError # print(wangwen) except IndexError: print("索引超出了范围") except KeyError: print("字典中没有这个键") except NameError: print("没有这个变量") except: print("有异常错误...")
:)看这个结构,有些像 if elif elif else的感觉
3.处理迭代器异常错误
def mygen(): print("start ... ") yield 1 yield 2 yield 3 return 4 gen = mygen() try: res = next(gen) print(res) res = next(gen) print(res) res = next(gen) print(res) res = next(gen) print(res) except StopIteration as e : # 为当前异常错误类StopIteration的对象起一个别名叫做e # 在StopIteration内部有__str__的方法 # 在打印对象时,直接获取生成器中的return的返回值. print(e) print("生成器停止迭代")
看到了这段代码,有几个问题需要注意:
1.except StopIteration as e:StopIteration是一个异常错误类,e是错误类对象的别名
2.在StopIteration异常类中,内置了__str__方法,在打印e对象时,可以直接获取到生成器中的return返回值
异常处理的其他写法
1.try ... finally ...
不论代码正确与否,都必须执行的代码放到finally当中.
一报错会终止掉程序,后面的代码不执行
有些必须要走的代码写在finally中
try: lst = [1,2,3] print(lst[90]) finally: print("被触发了..") print(123)
2.try ... except ... else ...
如果try这个代码块没有异常错误,执行else这个分支,反之就不执行
try: lst = [1,2,3] print(lst[90]) except: pass else: print("正常执行结束...")
3.try ... except ... else ... finally ...
try内代码块的代码如果有异常,执行except代码块
如果没有异常,执行else代码块
不管有没有异常,最后都要走finally代码块
try: lst = [1,2,3] print(lst[90]) except: print("异常处理222") else: print("正常执行结束...") finally: print("我被执行了111")
raise:主动抛出异常
关于raise你需要知道
基本格式:raise + 异常错误类 or 异常错误类对象
常见的两个父类:
BaseException 所有异常类的父类(基类,超类)
Exception 常见异常类的父类
raise的基本语法
# 基本语法 try: raise BaseException # 相当于主动制造出一个错误 except BaseException: pass # 简写 try: raise except: print("有异常错误")
自定义异常类
定义一个自定义异常类MyException,让此类继承BaseException类
#(了解)系统底层获取行数和文件名的函数( 只有在程序异常时才能触发 ) def return_errorinfo(n): import sys f = sys.exc_info()[2].tb_frame.f_back if n==1: return str(f.f_lineno) #返回当前行数 elif n == 2: return f.f_code.co_filename #返回文件名 def get_value(n): try: raise except: return return_errorinfo(n) class MyException(BaseException): def __init__(self,num,msg,line,file): # 错误号 self.num = num # 错误信息 self.msg = msg # 错误行号 self.line = line # 错误文件 self.file = file sex = "雌雄同体" try: if sex == "雌雄同体": # raise + 异常错误类 或者 异常错误类对象 raise MyException(404,"醒醒吧老弟,人类没有雌雄同体~",get_value(1),get_value(2)) except MyException as e: # 对象.属性 print(e.num) print(e.msg) print(e.line) print(e.file)
反射
概念: 通过字符串去操作类对象或者模块当中的成员(属性或者方法)
class Man(): pass class Woman(): pass class Children(Man,Woman): skin = "绿色" def eat(self): print("小孩一下生就拿了两串大腰子出来了") def drink(self): print("小孩一下生拿了两瓶勇闯天涯出来了") def __suger(self): print("小孩自个的糖糖是不给别人的...") obj = Children()
1.反射类当中的成员
1.hasattr() 检测对象/类是否有指定的成员
# hasattr() 检测对象/类是否有指定的成员 # 对象 res = hasattr(obj,"skin") # 检测obj对象是否有成员skin print(res) # 类 res = hasattr(Children,"eat") # 也可以检测类中是否有成员eat res = hasattr(Children,"__suger") # 私有成员不能访问,所以结果为False print(res)
2.getattr() 获取对象/类成员的值
# getattr() 获取对象/类成员的值 # 对象 res = getattr(obj,"skin") # 对象反射属性 print(res) # 通过对象反射出来的方法是个绑定方法,不需要在func添加参数,obj会自动传进去 func = getattr(obj,"drink") func() # 类 # 通过类反射出来的方法是个普通方法,需要添加参数,避免形参实参数量不一致 func = getattr(Children,"eat") func(1) # 反射的成员不存在时,可以设置一个默认值防止报错 res = getattr(obj,"abcdefg1234","该成员不存在") print(res)
3.setattr() 设置对象/类成员的值
# 对象 setattr(obj,"eye","白色") print(obj.eye) # 类 setattr(Children,"sex","女性") print(Children.sex) print(obj.sex)
4.delattr() 删除对象/类成员的值
delattr(obj,"eye") print(obj.eye) # error # 类 delattr(Children,"sex") Children.sex
2.反射模块当中的成员
import sys print(sys.modules) # 返回的是系统模块的一个字典 # 获取当前本模块的对象 (通过__main__这个键来获取) print(sys.modules["__main__"]) # <module '__main__' from '/mnt/hgfs/python31_gx/day27/mymodule4.py'> def func1(): print("我是func1方法") def func2(): print("我是func2方法") def func3(): print("我是func3方法") def func4(): print("我是func4方法")
3.反射综合案例
while True: selfmodule = sys.modules["__main__"] # 获取当前模块对象 strvar = input("请输入你要反射的方法") if hasattr(selfmodule,strvar): # 判断当前模块是否有你输入的方法 func = getattr(selfmodule,strvar) # 获取到你输入的方法名 func() else: print("没有这个方法")