生成器/异常处理
今日内容概要
- 异常常见类型/异常处理语法结构
- 异常处理实战应用
- 生成器对象/生成器底层原理
- yield冷门用法
- 生成器表达式及笔试题
1.异常处理语法结构
1.常见报错信息:
SyntaxError # 语法错误
NameError # 变量名错误
TypeError # 数据类型错误
IndentationError # 缩进错误
AttributeError: # 属性错误 特性引用和赋值失败时会引发属性错误。
IndexError: # 索引错误
KeyError: # 关键字错误
TabError: # Tab错误
以上是错误类型的具体图片解释
1.基本异常处理语法结构:
我们通过关键字 try
try:
待检测的代码(可能会报错的代码)
except 错误类型:
针对上述错误类型做出的处理(提前制定好方案)
2.查看错误信息:
try:
待检测的代码
except 错误类型 as e: # e为错误类型接收的变量名, 我们print(e) 就可以知道它是什么错误类型
针对上述错误类型做出的处理(提前制定好方案)
3.针对不同的错误信息使用不同的解决方案
try:
待检测的代码
except 错误类型 as e:
针对上述错误类型做出的处理(提前制定好方案)
except 错误类型1 as e1:
针对上述错误类型做出的处理(提前制定好方案)
except 错误类型2 as e2:
针对上述错误类型做出的处理(提前制定好方案)
4.万能异常处理:
try:
待检测的代码
except Exception as e:
针对各种常见的错误类型全部统一处理
5.try 也可以 与 else 结合使用
try:
待检测的代码
except 错误类型 as e:
针对上述类型错误做出的处理
else:
如果 try 的子代码正常结束运行没有被 except 检测 那么就会走 else 下面的子代码
6.finally
try:
待检测的代码
except 错误类型 as e:
针对上述类型错误做出的处理
else:
try的子代码正常结束运行没有走 except 那么就会走 else 下面的子代码
finally:
无论 try 走 except 或 else 下面的子代码, 只要有 finally 就都会走 finally 下面的子代码
# 异常处理补充:
1. 断言
name = 'xiaoming'
# assert isinstance(name, int)
assert isinstance(name, str) # 判断name绑定的数据值'小明' 是否是字符串类型
print('是的他就是字符串') # 如果是字符串类型的话就会往下走,否则就会报错
assert 就是断定 后面的代码没问题,如果有问题报错,没问题继续往下执行
2.主动抛异常(自定义BUG)
a = 'name'
if a == 'name'
raise Exception('呵呵') # 自定义错误类型
else:
print('啥事没有')
异常处理实战
1.异常处理能少用就少用
2.被 try 检测的代码不要太多,尽量减少
3.当代码中可能出现一些无法控制的报错情况才会使用异常处理解决
比如 # 编写网络爬虫程序请求数据 断网
4.小小练习题:
我们现在也了解了异常处理方式,迭代器对象的概念,可迭代对象如果转换迭代器
那么我们可以思考一下 如何用 while 循环 + 异常处理 +迭代器对象 实现for循环的功能
l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99]
# 1.我们先把l1 变成迭代器对象
l1_iter = l1.__iter__()
# 2. 我们通过 while循环 加上 __next__方法进行取值
while True:
try:
print(l1_iter.__next__()) # 打印 l1_iter.__next__() 从迭代器中取出的值
except StopIteration as e: # 捕获StopIteration错误类型 并结束循环
break
2.生成器对象
1.本质
生成器还是内置含有__iter__(),__next__()的迭代器对象
2.区别
迭代器对象是解释器自动提供的 # 可迭代的数据类型有__iter__()
生成器对象是我们自己根据需求自定义创建的 # 代码(函数)、关键字
3.创建生成器的基本语法
函数体代码中填写 yield 关键字
def my_func():
print('good morning')
yield
如果定义函数内部的函数体代码有 yield 关键字 那么它的调用 函数名加() 不会立刻执行函数体代码
而是生成一个生成器对象(迭代器对象)
res = my_func()
print(res) # <generator object my_func at 0x000002304010CC80> 生成器的内存地址
res.__next__() # 运行函数体代码 并且到 yield 关键字时结束, 下一次使用__next__()方法时从yield开始 并寻找下一个 yield 关键字
def user_iter():
print('用户1')
yield 'pwd:123'
print('用户2')
yield 'pwd:321'
print('用户3')
yield 'pwd:222'
print('用户4')
yield 'pwd:999'
data = user_iter() # 生成器对象 为 data
# print(data)
b = data.__next__() # 先调用.__next__()方法并且获得yield关键字的返回值赋值给b
print(b)
c = data.__next__() # 先调用.__next__()方法并且获得yield关键字的返回值赋值给c
print(c)
d = data.__next__() # 先调用.__next__()方法并且获得yield关键字的返回值赋值给d
print(d)
e = data.__next__() # 先调用.__next__()方法并且获得yield关键字的返回值赋值给e
print(e)
4.小小练习题:
自定义生成器对标range功能(一个参数 两个参数 三个参数 迭代器对象)
def my_range_func(start_num, end_num=None, step=1):
if step > 0:
if not end_num:
end_num = start_num # 这是当参数为1的时候 让end_num有赋值
start_num = 0 # 然后把0赋值给start_num 因为range是前取后不取
while start_num < end_num: # 当start_num <end_num 时结束循环
yield start_num # 直接通过关键字yield返回 start_num
start_num += step # 每次取值都让start_num + step
elif step == 0:
raise ValueError('range() arg 3 must not be zero') # 抛出BUG
else:
if start_num < end_num: # 如果参数1 小于 参数2
while start_num < end_num: # 循环条件也是如此
yield end_num # 返回 参数2
end_num += step # 参数2 - 步长的绝对值
elif start_num > end_num: # 如果 参数1 大于 参数 2
while start_num > end_num: # 循环条件也是如此
yield start_num # 返回 参数1
start_num -= abs(step) # 参数1 - 步长的绝对值
for i in my_range_func(0,100,0):
print(i)
print(my_range_func(10, 50, 0).__next__())
3.yield冷门用法
# 生成器也是可迭代对象我们也可以通过for 循环依次进入生成器中取值
def data(user, skills=None):
print(f'{user}准备使用')
while True:
skills = yield # 通过sned方法获取数据 并赋值给前面的skills变量名
print(f'{user}正在使用{skills}')
res = data('tom')
res.__next__()
res.send('R:天崩地裂') # send() 将括号内的数据传给yield前面的变量名 2.再自动调用__next__
res.send('W:横扫千军')
4.生成器表达式
我们只需要把列表生成式外面的[] 换成 元组的()
就可以了
这样我们就得到了一个生成器
并且它是可迭代对象,支持被for循环遍历
res = (i+i for i in range(20))res = (i*i for i in range(20))
for i in res:
print(i)
附赠面试题:
def add(n, i): # 普通函数 返回两个数的和 求和函数
return n + i
def test(): # 生成器
for i in range(4):
yield i
g = test() # 激活生成器
for n in [1, 10]:
g = (add(n, i) for i in g)
"""
第一次for循环
g = (add(n, i) for i in g)
第二次for循环
g = (add(10, i) for i in (add(10, i) for i in g))
"""
res = list(g)
print(res)
#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23]
#D. res=[21,22,23,24]