异常捕获和生成器
目录
-
异常捕获
1.什么是异常
2.异常的结构
3.异常的常见类型
4.异常的分类
5.处理异常捕获的关键字及作用 -
生成器
1.生成器对象的本质
2.生成器对象的目的
3.生成器对象的实现
4.课题小练习
5.yield的其他用法
6.生成器表达式
异常捕获
-
什么是异常
异常就是在程序运行阶段遇到逻辑或语法错误而导致程序终止。 -
异常的结构
1.关键字 line 所在行
精准提示哪行代码出现问题
2.最后一行冒号左侧
错误的类型
3.最后一行冒号右侧
错误的具体原因(也是改BUG的关键) -
异常的常见类型
NameError
IndexError
KeyError
SyntaxError
TypeError -
异常的分类
-
语法错误
语法错误就是在程序端中只有输入或输出的错误
-
逻辑错误
逻辑错误就是在程序中所体现的逻辑层面的错误
-
处理异常捕获的关键字及作用
关键字 关键字说明 try/excrpt 捕获异常并处理 pass 忽略异常 as 定义到异常的实例 Exception/BaseException 包容所有错误类型,不会出现类型不对应而产生的程序错误 else 如果try中的语句没有引发异常,则执行else中的语句 finally 无论是否出现异常,都执行的代码(一般放在最后) assert 断言,用assert isinstance()断言数据属于什么类型,不对报错,反之正常运行 raise 抛出/引发异常
- 捕获异常的基本语法
try:
可能会出错的代码(被try监控)
except 错误类型1 as e: # e就是具体错误的原因
对应错误类型1的解决措施
except 错误类型2 as e: # e就是具体错误的原因
对应错误类型2的解决措施
except 错误类型3 as e: # e就是具体错误的原因
对应错误类型3的解决措施
except 错误类型4 as e: # e就是具体错误的原因
对应错误类型4的解决措施
使用try 方法 来将逻辑错误跳过使程序正常运行,as的作用就是承接错误的原因,如若except后面的错误类型与其不对应,那么程序也会报错。
- 捕获异常的万能捕获方法
try:
错误类型
except Exception as e: # 万能异常方式1
print(e)
except BaseException as e: # 万能异常方式2
print(e)
使用Exception/BaseException 可以包容所有错误类型,不会出现类型不对应而产生的程序错误
- 异常中的else和finally
try:
name
except Exception as e:
print('你出错了 你个小垃圾')
else:
print('try监测的代码没有出错的情况下正常运行结束 则会执行else子代码')
finally:
print('try监测的代码无论有没有出错 最后都会执行finally子代码')
使用else时,只有上述代码没有出错,正常运行结束后才能运行else后面的子代码。与while 、for、if 用法一致。
使用finally时,无论上述代码有没有出错,都能运行其后面的子代码。
- 异常中的断言
name = 'jason' # 通过一系列的手段获取来的数据
assert isinstance(name, list) # 断言数据属于什么类型 如果不对则直接报错 对则正常执行下面的代码
print('针对name数据使用列表相关的操作')
断言数据属于什么类型 如果不对则直接报错 对则正常执行下面的代码
- 异常中的主动抛出/引发异常
name = input('username>>>:').strip()
if name == 'jason':
# raise NameError('jason来了 快跑!!!')
raise Exception('反正就是不能过')
else:
print('不是jason 那没事了')
每次执行 raise 语句,都只能引发一次执行的异常。此次异常是主动定义的。
生成器
-
生成器对象的本质
生成器就是自己定义出来的,其本质就是迭代器对象
使用方法__ iter __ 和 __ next __ -
生成器对象的目的
目的就是为了优化代码
生成器可以节省数据类型的内存占用空间,是一种不依赖索引取值的通用方式 -
生成器对象的代码实现
# def index():
# print('我是谁呀 嘿嘿嘿~')
# yield 111, 222, 333
# print('你追我 如果你追到我 我就... 嘿嘿嘿~')
# yield 222
# print('实在跑不动了 嘿嘿嘿~')
# yield 333
"""
当函数体代码中有yield关键字
那么函数名第一次加括号调用不会执行函数体代码
而是由普通的函数变成了迭代器对象(生成器) 返回值
"""
# print(index) # <function index at 0x000001F499F7A5E0>
# res = index()
# print(res) # <generator object index at 0x0000021E18BACA50>
# res.__next__()
# res.__next__()
# res.__next__()
"""
yield可以在函数体代码中出现多次
每次调用__next__方法都会从上往下执行直到遇到yield代码停留在此处
"""
# print(res.__next__())
# print(res.__next__())
# print(res.__next__())
# print(res.__next__())
"""
yield后面如果有数据值 则会像return一样返回出去
如果有多个数据值逗号隔开 那么也会自动组织成元组返回
"""
当函数代码中有yield关键字时,函数名第一次加括号调用不会执行函数体代码,而是变成了生成器返回值
定义后方可使用。
yield 在函数体代码中可多次使用,每次调用__ next __方法都会从上往下直到遇见yield代码停留在此处
如果 yield后面有数值,则会像return一样返回出去,若有多个数值,则自动组织成元组的形式。
当调用的次数多于yield时,则会出现报错
- 课题小练习
# 编写生成器 实现range方法的功能
def my_range(start_num, end_num=None, step=1): # my_range(1,10,3)
if step < 1:
step = 1
if not end_num:
end_num = start_num
start_num = 0
while start_num < end_num:
yield start_num
start_num += step
# for i in my_range(1, 100, 2):
# print(i)
# for i in my_range(1, 5):
# print(i)
# for i in my_range(10):
# print(i)
for i in my_range(1, 100, -2):
print(i)
- yield的其他用法
def index(name,food=None):
print(f'{name}准备干午饭!!!')
while True:
food = yield
print(f'{name}正在吃{food}')
res = index('jason')
res.__next__()
res.send('生蚝') # 传值并自动调用__next__方法
res.send('韭菜') # 传值并自动调用__next__方法
res.send('腰子') # 传值并自动调用__next__方法
针对表达式形式的yield,生成器对象必须事先被初始化一次,让函数挂起在food=yield的位置,等待调用res.send()方法为函数体传值
表达式形式的yield也可以用于返回多次值,即 变量名=yield 值 的形式
- 生成器表达式
创建一个生成器对象有两种方式,一种是调用带yield关键字的函数,另一种就是生成器表达式,与列表生成式的语法格式相同,只需要将[]换成(),生成器表达式返回的是一个生成器对象即:
l1= [x*x for x in range(3)]
[0, 1, 4]
l1 =(x*x for x in range(3))
print(l1)