今日内容
异常捕获
思考
1.如何理解异常?
代码程序出现出现错误,异常而导致整个程序的停止,俗称‘bug’
- 异常的结构
eg:
name
Traceback (most recent call last):
File "D:/pythonProject/day21/01 生成器.py", line 13, in <module>
name
NameError: name 'name' is not defined
结构解释
1.关键字line:
提示你异常在哪一行,当我们点File后面的蓝色字体,会自动跳转到异常的代码行
2.最后一行冒号的左边
eg:
NameError
:代表错误的类型3.最后一行冒号的右边
代码错误的主要原因(改bug的关键)
- 异常的类型
类型 | 描述 |
---|---|
NameError | 找不到指定名称的变量的时候,出现的错误 |
IndexError | 当使用超出列表范围的索引的时候,出现的错误 |
KeyError | 当使用不存在的键的时候,出现的错误 |
SyntaxError | 发生语法错误的时候,出现的错误 |
TypeError | 当在使用这种类型的场合使用另外一种类型的时候,出现的错误 |
- 异常的分类
1.语法错误
不允许出现的错误,如果发现一定要及时改正
2.逻辑错误
这个是允许出现的,在发现之后修改即可
以后工作中,我们自己写完代码之后,一定要自己先测试一遍后再提交
异常捕获实参演练
思考
1.什么时候才可能会需要自己写代码处理异常?
当我们在写代码的时候,感觉这部分会报错的情况下使用
*2.如何使用异常捕获?
相当于是提前预测可能出现的问题并提前给这一部分代码进行处理
- 异常捕获的代码实现
基本语法结构
eg:
try:
可能会出现错误的代码
except 错误的类型 as e:
对应错误类型做出的措施
如果你也不确定错误的类型的话,我们可以这样
eg:
try:
可能会出现错误的代码
except 错误的类型1 as e:
对应错误类型1做出的措施
except 错误的类型2 as e:
对应错误类型2做出的措施
except 错误的类型3 as e:
对应错误类型3做出的措施
- 万能异常
关键字:Exception
在你不知道异常类型,又不想写那么多代码的情况下,可以使用
举例说明
eg:
try:
name = 'jason'
123 + name
except Exception as e:
print(e)
输出结果:
unsupported operand type(s) for +: 'int' and 'str'
注意:如果出现的是语法错误的时候,使用异常处理的时候还是会正常报错
eg:
try:
if
except Exception as e:
print(e)
输出结果:
File "D:/pythonProject/day21/01 生成器.py", line 23
if
^
SyntaxError: invalid syntax # SyntaxError语法错误
- 异常捕获其他操作补充
try + else + finally
eg:
try:
name = 'jason'
123 + name
except Exception as e:
print(e)
else:
print('走我这吗?') # 如果可能异常的代码是正确的走这
finally:
print('都要走我这') # 这里是有没有异常都会走这的
输出结果:
unsupported operand type(s) for +: 'int' and 'str'
都要走我这
可能异常代码正确
eg;
try:
name = 'jason'
except Exception as e:
print(e)
else:
print('走我这吗?')
finally:
print('都要走我这')
输出结果:
走我这吗?
都要走我这
断言
eg:
name = 'jason'
assert isinstance(name, list) # name是list吗?不是
print('是这吗?') # 当判断正确的时候,会走这
输出结果:
Traceback (most recent call last):
File "D:/pythonProject/day21/01 生成器.py", line 33, in <module>
assert isinstance(name, list)
AssertionError
主动异常
关键字:raise
eg:
name = input('请输入你的姓名:')
if name == 'jason':
raise Exception('快跑')
else:
print('没事了')
输出结果:
请输入你的姓名:jason
Traceback (most recent call last):
File "D:/pythonProject/day21/01 生成器.py", line 42, in <module>
raise Exception('快跑')
Exception: 快跑
请输入你的姓名:kevin
没事了
注意:异常捕获用的越少越好;被try检测的越来越少越好
- for循环内部的本质
l1 = [11, 22, 33, 44, 55, 66, 77, 88]
res = l1.__iter__()
while True:
try:
print(res.__next__()) # 循环输出值
except Exception as e: # 如果列表中的值取完了,自动报错,异常捕获
break # 然后结束
生成器对象
-
本质
其实就是迭代器对象,只不过迭代器是解释器提供给我们的 生成器是需要我们自己写的
思考
生成器的作用
也是为了节省内存空间,优化代码
一种不依赖于索引取值的方法
其实生成器是基于yield返回值的函数,支持通过双下next不断取下一个值
-
生成器的优点和特点
优点: 节省内存, 生成器本身就是代码. 几乎不占用内存 特点: 惰性机制, 只能向前. 不能反复
-
生成器代码实现
举例说明
eg:
def index(): print(123) yield res = index() # 这里不是真正的调用输出,因为这里是yield将函数变为了生成器 res.__next__() # 123 通过双下next输出 res.__next__() # 没有值可取,报错
eg2:
def index(): print(123) yield print(321) yield res = index() res.__next__() # 123 当运行到第一个yield停住,直到下一个双下next的出现 res.__next__() # 321 双下next继续输出
yield后面也可以返回值
eg:
def index(): print(123) yield 222 print(321) yield 333 res = index() print(res.__next__()) # 123 222 print(res.__next__()) # 321 333
总结
1.当函数中出现yield的时候,那么函数名加括号第一次调用的时候是不会执行函数体代码的,而是将函数转换为生成器,也可以返回值
2.yield也可以有多个,每次执行完一次双下next的时候都会停留在yield,等着下一个双下next的出现
3.如果yield后面有数据值的时候,也可以像return一样返回出去,如果有多个的值的时候,也是以元组的形式返回
eg:
def index(): print('jason') yield print(index) # <function index at 0x0000020AD8D71E18> 函数 res = index() # 并没有执行函数体代码,而是将函数转换为生成器 print(res) # <generator object index at 0x0000020AD8EB1CA8> 生成器
课堂练习
-
编写生成器,实现range的功能
代码:
def index(start, end=None, step=2): if step < 1: # 因为间隔数不能为负数 step = 1 # 为负数,重新定义值 if not end: # None对应的布尔值为False end = start # 如果只有一个参数的时候,让开始的那个数字等于end start = 0 # 然后让开始数为0 while start < end: # 条件 yield start # 返回出值 start += step # 自增 for i in index(100): # 循环在生成器中取值 print(i)
yield其他用法
举例说明
eg:
def index(name, food=None):
print(f'{name}吃饭')
while True:
food = yield
print(f'{name}正在吃{food}')
res = index('jason') # 传参,转换为生成器
res.__next__() # 输出,并停留在yield
res.send('蛋糕') # 给yield传数据值
send可以给yield传数据值
生成器表达式
我们可以用元组的生成式来演示
结构:
(结果 for循环 if)
eg:
l1 = [i * 2 for i in range(10) if i > 5]
print(l1) # [12, 14, 16, 18] 列表生成式
l1 = (i * 2 for i in range(10) if i > 5)
print(l1) # <generator object <genexpr> at 0x0000018001F71CA8> 生成器
-
相关面试题
eg:
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] 正确答案:C