学习python-Day19
今天学习内容
一、异常捕获
-
异常简介
程序在运行过程中如果出现了异常就会导致整个程序的结束
异常就是程序员口中的
bug -
异常结构
D:\python38\python.exe D:/pythonProject/kaoshi/one.py Traceback (most recent call last): File "D:/pythonProject/kaoshi/one.py", line 1, inusername NameError: name 'username' is not defined 描述 关键字line所在行 精准提示你在哪一行代码出错 最后一行冒号左侧 表示错误类型 最后一行冒号右侧 错误的具体原因(也是修bug的关键) -
异常类型
异常名称 描述 BaseException 所有异常的基类(父类) SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入) Exception 常规错误的基类() StopIteration 迭代器没有更多的值 GeneratorExit 生成器(generator)发生异常来通知退出 StandardError 所有的内建标准异常的基类 ArithmeticError 所有数值计算错误的基类 FloatingPointError 浮点计算错误 -
异常分类
语法错误:语法结构不对,python会报错误。不允许出现,一旦出现就立刻修改。逻辑错误:运行前看不出来错误,运行后就会出现。允许出现,出错之后修改即可。
-
异常捕获练习
-
什么时候才可能会需要自己写代码处理异常
-
异常捕获:提前预测可能出现的问题并提前给出处理的措施 -
异常捕获代码实现
1.基本语法结构(针对性很强) try: 可能会出现的代码(被try监控) except 错误类型1 as e: # e就是具体错误的原因 对应错误类型1的解决措施 except 错误类型21 as e: # e就是具体错误的原因 对应错误类型2的解决措施 except 错误类型3 as e: # e就是具体错误的原因 对应错误类型3的解决措施 except 错误类型4 as e: # e就是具体错误的原因 对应错误类型41的解决措施 2.万能异常(笼统的处理方式) try: #name # d = {'name': 'jason'} # d['pwd'] 123 + 'hello' except Exception as e: # 万能异常方式1 print(e) except BaseException as e: #万能异常方式2 print(e) 3.异常捕获其他操作补充 3.1 else | finally try: name except Exception as e: print('你出错了!') else: print('try监测的代码没有出错的情况下正常运行结束,则会执行else子代码') finally: print('try监测的代码无论有没有出错,最后都会执行finally子代码') 3.2断言 name = 'xz' # 通过一系列手段获取来的数据 assert isinstance(name,list) # 断言数据属于什么类型,如果不对则直接报错,对则正常执行下面的代码 print('针对name数据使用列表相关的操作') 3.3主动抛出异常 name = input('username>>>:').strip() if name == 'xz': # raise NameError('xz长得好帅!!!!') raise Exception('反正就是长得帅!!!') else: print('不是xz,那就走吧') 注意: 1.异常捕获能尽量少用就尽量少用 2.被try监测的代码能尽量少就尽量少 因为如果try包含的代码太多,监测太多的话会影响运行也会占资源。 4.异常捕获练习 for循环内部的本质 #需求:使用while + 异常捕获实现for循环的功能 l1 = [11, 22, 33, 44, 55, 66, 77, 88] res = l1.__iter__() #将列表变成可迭代对象,赋值给res while True: try: print(res.__next__())# res循环调用__next__变成可迭代器对象。监测可能出现异常的部分 except Exception as e: break#监测出就里面结束 如果一个项目出现错误我们可以分几步来解决问题: 1.先看具体的报错信息,报红的地方。 2.再看具体的定位信息,有下往上看。 3.尽量将错误缩小到某个具体的变量 4.注意力就关注在出现这个变量的代码身上即可
-
二、生成器对象(自定义迭代器对象)
-
本质
就是迭代器对象。只不过迭代器是解释器提供给我们的(现成的)。
生成器是我们自定义出来的(自己动手编写)。
-
目的
就我为了优化代码。一种不依赖索引取值的通用方式。
可以
节省数据类型的内存占用空间(空间)。 -
代码
def index(): print('你好!') yield xz, wyb print('很高兴认识你们!') yield aaaa print('未来可期!') yield hhhh print(index) #还是属于函数,函数名第一次加括号调用不会执行函数体代码 res = index() #由普通函数变成了迭代器对象(生成器) 将返回值赋值给变量名 print(res) #生成器 res.__next__() res.__next__() res.__next__() '运行结果:你好! 很高兴认识你们! 未来可期! ' ''' 当代码有yield关键字 那么函数名第一次加括号调用不会执行函数体代码 而是由普通的函数变成了迭代器对象(生成器)将返回值赋值给变量名。 ''' ''' yield可以在函数代码中出现多次 每次调用__next__方法都会从上往下执行直到遇到yield代码停留在此处 ''' 将上述的res.__next__()都去掉。 print(res.__next__()) print(res.__next__()) print(res.__next__()) '运行结果:你好! (11, 22) 很高兴认识你们! 333 未来可期! 444 ' print(res.__next__()) #如果再加一个,会报错。超过了它的取值范围,没有yield了。 ''' yield后面如果有数据值,则会像return一样返回出去 如果有多个数据值逗号隔开,那么也会自动组织成元组返回。 ''' -
课堂练习
编写生成器,实现range方法的功能 1.可以先先两个参数的功能编号 range(1,10) def my_range(start_num, end_num): while start_num -
yield
def index(name, food=None): print(f'{name}准备放假!!!') while True: food = yield #send就是传值给yield赋值左边的变量名。 print(f'{name}准备放假!!!回{food}') res = index('xz') res.__next__() #调用__next__()方法 res.send('北京') #传值并调用__next__方法 res.send('上海') #传值并调用__next__方法 res.send('深圳') #传值并调用__next__方法 '运行结果: xz准备放假!!! xz准备放假!!!回北京 xz准备放假!!!回上海 xz准备放假!!!回深圳 '
三、生成器表达式
#列表生成式 中括号
l1 = [i**2 for i in range(10) if i > 3]
print(l1)
#生成器 将中括号变成小括号
l1 = (i**2 for i in range(10) if i > 3)
print(l1)
'运行结果:
[16, 25, 36, 49, 64, 81]
at 0x000001C937BF4970>
'
===面试试题====
#普通就和函数
def add(n,i):
return n + i
#生成器对象 返回 0 1 2 3
def test():
for i in range(4)
yield i
#将test函数变成生成器
g = test()
#简单的for循环
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)) #n为10
所以两个n相加最少为20
里面代码只有对迭代取值的时候才有用
'''
#list底层就是for循环,相当于对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