【python基础】第23回 异常捕获 生成器
本章内容概要
1. 异常捕获
2. 异常捕获实参练习
3. 自定义迭代器对象(生成器)
4. 编写生成器 实现range方法的功能
本章内容详情
1. 异常捕获
1.1 如何理解异常
程序再运行的过程中如果出现了异常会导致整个程序的结束,异常就是程序员口中的bug
1.2 异常结构
1. 关键字line所在行,精准提示你哪一行代码出错
2. 最后一行冒号左侧,是错误类型
3. 最后一行冒号右侧,错误的具体原因(也是改bug的关键)

1.3 异常的分类
1. 语法错误
不允许出现的 一旦出现请立刻修改
2. 逻辑错误
允许出现的 允许出错之后修改即可
1.4 异常的类型
| 异常名称 | 描述 |
| BaseException | 所有异常的基类 |
| IndexError | 索引错误 |
| keyError | 键错误 |
| SyntaxError | 语法错误 |
| TypeError | 类型错误 |
| IndentationError | 缩进错误 |
| NameError | 名称错误 |
| ImportError | 导入模块/对象错误 |
| IOError | 输入/输出操作失败 |
| OSError | 操作系统错误 |
2. 异常捕获实参练习
2.1 什么时候才可能需要自己写代码处理异常
当代码不确定什么时候会报错的情况下
eg:编写网络爬虫访问网址数据并处理 有可能会出现断网,数据没有处理不了
2.2 异常捕获的使用相当于是提前预测可能出现的问题并提前给出处理的措施
2.3 语法结构
try: 可能会出现错的代码(被try监控) except 错误类型1 as e: # e就是具体错误的原因 对应错误类型1的解决措施 可能会出现错的代码(被try监控) except 错误类型2 as e: # e就是具体错误的原因 对应错误类型1的解决措施 可能会出现错的代码(被try监控) except 错误类型3 as e: # e就是具体错误的原因 对应错误类型1的解决措施 可能会出现错的代码(被try监控) except 错误类型4 as e: # e就是具体错误的原因 对应错误类型1的解决措施
2.4 万能异常(笼统的处理方式)
try: name # d = {'name':'jason'} # d['pwd'] # 123 + 'hello' except Exception as e: # 万能异常方式1 print(e) except BaseException as e: # 万能异常方式2 print(e)
2.5 else 与 finally
try: name except Exception as e: print('出错') else: print('try监测的代码没有出错的情况下正常运行结束,则会执行子代码') finally: print('try监测的代码无论有没有出错 最后都会执行finally子代码')
2.6 断言
name = 'jason' # 通过一系列的手段获取来的数据 assert isinstance(name, list) # 断言数据属于什么类型 如果不对则直接报错 对则正常执行下面的代码 print('针对name数据使用列表相关的操作')
2.7 主动抛异常
name = input('username>>>:').strip() if name == 'jason': # raise NameError('jason来了 快跑!!!') raise Exception('抛出异常') else: print('正常')

2.8 强调
1. 异常捕获能尽量少用就经量少用
2.被try监测的代码能尽量少就尽量少
2.9 for循环内部的本质
# 使用while+异常捕获实现for循环的功能 l1 = [11, 22, 33, 44, 55, 66] res = l1.__iter__() while True: try: print(res.__next__()) except Exception as e: break
3. 自定义迭代器对象(生成器)
3.1 本质其实就是迭代器对象
只不过迭代器是解释器提供给我们的(先成的) 生成器是我们自己定义出来的(自己动手)
3.2 学习生成器对象的目的是为优化代码
2种功能,一种不依赖于索引取值的通用方式,可以节省数据类型的内存占用空间(主要)
3.3 生成器表达式
# 列表 l1 = [i**2 for i in range(10) if i > 3] print(l1) # [16, 25, 36, 49, 64, 81] # 生成器 l1 = (i**2 for i in range(10) if i > 3) print(l1) # <generator object <genexpr> at 0x000001A793439C10>
3.4 生成器对象代码实现
1. 但函数体代码中有yield关键字,那么函数名第一次加括号调用不会执行函数体代码,而是由普通的函数变成了迭代器对象(生成器) 返回值
2. yield可以在函数体代码中出现多次,每次调用__next__方法都会从上往下执行直到遇到yield代码停留在此处
3. yield后面如果有数据值 则会像return一样返回出去,如果有多个数据值逗号隔开 那么也会自动组织成元组返回
def index(): print('第一') yield 11,22 print('第二') yield 22 print('第三') yield 33 print(index) # <function index at 0x0000027CC9AFA4C0> res = index() print(res) # <generator object index at 0x000001CDBB46BA50> res.__next__() res.__next__() res.__next__()

def index(): print('第一') yield 11,22 print('第二') yield 22 print('第三') yield 33 print(index) # <function index at 0x0000027CC9AFA4C0> res = index() print(res) # <generator object index at 0x000001CDBB46BA50> # res.__next__() # res.__next__() # res.__next__() print(res.__next__()) print(res.__next__()) print(res.__next__())

3.5 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__方法

4. 编写生成器 实现range方法的功能
4.1 可以先以两个参数的功能编写
# 1.可以先以两个参数的功能编写 range(1,10) def my_range(start,end): while start < end: yield start start += 1 for i in my_range(1, 10): print(i)
4.2 再考虑一个参数
# 2.再考虑一个参数的情况 range(10) range(0,10) def my_range(start, end=None): if not end: end = start start = 0 while start < end: yield start start += 1 for i in my_range(5): print(i)
4.3 最后考虑三个参数的情况
# 3.最后考虑三个参数的情况 range(1, 10, 2) def my_range(start, end=None, step=1): if step < 1: step = 1 if not end: end = start start = 0 while start < end: yield start start += step for i in my_range(1, 10, 2): print(i)

浙公网安备 33010602011771号