A-Z 65 -90
a-z 97-122
迭代取值 = for循环取值(每次取值都依赖于上一次取值)
python基础之异常处理、生成器对象、生成器表达式
一、异常处理语法结构
1.异常的常见类型
| 1.语法错误 |
| if 后面没东西 |
| SyntaxError:invalid syntax |
| 2.名字错误 |
| name 没有赋值 |
| NameError |
| 3.索引错误 |
| l1 = [1,3,4] |
| l1[100] |
| IndexError |
| 4.字典关键字错误 |
| d1={'name':'duo'} |
| d1['age'] |
| KeyError关键字错误 |
| 5.缩进错误 |
| IndentationError缩进错误: unexpected indent |
2.异常处理语法结构
| 1.语法结构 |
| try: |
| 待监测的代码(可能会出错的代码) |
| except 错误类型: |
| 针对上述错误类型制定的方案 |
| |
| |
| try: |
| name |
| except NameError: |
| print('名字没被定义') |
| |
| 2.查看错误的类型 |
| try: |
| 待监测的代码(可能会出错的代码) |
| except 错误类型 as e: |
| 针对上述错误类型制定的方案 |
| print(e) |
| |
| 3.针对不同的错误类型制定不同的解决方案** |
| |
| try: |
| 待监测的代码(可能会出错的代码) |
| except 错误类型1 as e: |
| 针对上述错误类型1制定的方案 |
| |
| except 错误类型2 as e: |
| 针对上述错误类型2制定的方案 |
| |
| except 错误类型3 as e: |
| 针对上述错误类型3制定的方案 |
| |
| |
| 4.万能异常** |
| try: |
| 待监测的代码(可能会出错的代码) |
| except Exception as e: |
| |
| |
| print(e) |
| 针对上述不同的错误类型统一处理 |
| |
| 5.try 结合 else使用: |
| try: |
| 待监测的代码(可能会出错的代码) |
| except Exception as e: |
| print(e) |
| 针对上述不同的错误类型统一处理 |
| else: |
| try的子代码正常运行结束没有任何报错后,再执行else子代码 |
| |
| 6.try 结合 finally使用 |
| |
| finally: |
| 无论try的子代码是否报错,最后都要执行finally子代码 |
| |
3.异常处理补充
| 1.assert 断言 |
| assert 提前判断是否符合要求,是的话就继续往下走,不是的话就会报错 |
| |
| |
| |
| name = 'duo' |
| assert isinstance(name, int) |
| print('is str') |
| |
| name = 'duo' |
| assert isinstance(name, str) |
| print('is str') |
| |
| |
| 2.raise 主动抛异常 |
| 关键字 raise |
| |
| name = 'duo' |
| if name == 'duo': |
| raise Exception('主动报错') |
| else: |
| print('代码继续走') |
4.异常处理实战应用
| |
| 1.异常处理能尽量少用(try子代码监测会占用一定的资源) |
| 2.被try监测的代码越少越好 |
| 3.当代码中可能会出现一些无法控制的情况报错 才应该考虑使用 |
| |
| |
| 课堂练习: |
| |
| 使用while 循环+ 异常处理+迭代器对象,完成for循环迭代取值的功能 |
| |
| |
| l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99] |
| res = l1.__iter__() |
| while True: |
| try: |
| res1 = res.__next__() |
| print(res1) |
| except StopIteration as e: |
| break |
| |
| |
| l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99] |
| |
| |
| res = l1.__iter__() |
| |
| while True: |
| |
| try: |
| print(res.__next__()) |
| |
| except StopIteration as e: |
| break |
三、生成器对象
1.生成器对象的本质
| 1.本质 |
| 还是内置有__iter__和 __next__的迭代器对象 |
| |
| 生成器对象定义了一个__next__方法,它要么返回迭代中的下一项,要么引发一个特殊的StopIteration异常来终止迭代,一个可迭代对象的迭代器用iter内置函数来接收值。 |
| |
| 生成器是python中的一个对象(按照某种规律,来生成元素的对象),生成器不是列表,保存了产生元素的算法,同时会记录游标的位置(现在拿到第几个元素了) |
| ,为了下次继续拿数据,而不是从头开始拿数据。可以通过一直调用next()方法获取值,这个对象不保存数据,每次调用会返回一个值,即做到了列表的好处,又不占用空间。 |
| |
2.语法
| |
| 2. 迭代器对象 和 生成器对象的 区别 |
| |
| 1)迭代器对象是解释器自动提供的 |
| 数据类型、文件对象 >>>: 迭代器对象 |
| 2)生成器对象是程序员自己写出来的 |
| 代码、关键字 >>>: 迭代器对象(生成器) |
| 3.创建生成器的语法(生成器函数) |
| |
| 函数体代码中加一个 yield关键字 |
| |
| |
| def my_iter(): |
| print('duoduodudoudouodo') |
| yield |
| |
| ''' |
| 1 函数体代码中如果有yield关键字, |
| 那么函数名加括号并不会执行函数体代码 |
| 会生成一个生成器对象 |
| ''' |
| my_iter() |
| res = my_iter() |
| ''' |
| 2 使用加括号之后的就能够调用__next__才会执行函数体代码 |
| |
| ''' |
| res.__next__() |
| ''' |
| 3 每次执行完__next__代码都会停在yield位置, |
| 下次基于该位置继续往下找第二个yield |
| ''' |
| res.__next__() |
| |
| def my_iter(): |
| print('duoduodudoudouodo') |
| yield 111 |
| print('2222') |
| yield 222 |
| print('3333') |
| yield 333 |
| print('4444') |
| yield 444 |
| |
| res = my_iter() |
| r1 = res.__next__() |
| print(r1) |
| res.__next__() |
| res.__next__() |
| res.__next__() |
| ''' |
| 4 yield有点类似于return 可以返回返回值 |
| ''' |
3.生成器详细
| 1.若函数体包含yield关键字,再调用函数,并不会执行函数体代码,得到的返回值即生成器对象 |
| |
| def my_range(start, stop, step=1): |
| print('start...') |
| while start < stop: |
| yield start |
| start += step |
| print('end...') |
| |
| |
| g = my_range(0, 3) |
| print(g) |
| |
| |
| 2.生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器 |
| |
| print(g.__iter__) |
| |
| print(g.__next__) |
| |
| 3.可以触发函数执行直到yield停止,将yield后的值返回,并将当前函数挂起,再次调用__next__方法,函数从上次暂停的位置继续执行 |
| |
| r1 =g.__next__() |
| print(r1) |
| r2 =g.__next__() |
| print(r2) |
| r3 =g.__next__() |
| print(r3) |
| r4 = g.__next__() |
| |
四、用生成器对象实现range方法
| 自定义生成器对标range功能(一个参数 两个参数 三个参数 利用迭代器对象) |
| |
| 1.先写两个参数的 |
| def my_range(start_num, end_num): |
| while start_num < end_num: |
| yield start_num |
| start_num += 1 |
| |
| for i in my_range(1, 10): |
| print(i) |
| |
| |
| res = my_range(1, 10).__iter__() |
| while True: |
| try: |
| print(res.__next__()) |
| except StopIteration: |
| break |
| |
| |
| 2.增加参数和判断条件,实现range有一个参数和三个参数的功能 |
| |
| def my_range(start_num, end_num=None, 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, 10, 2): |
| print(i) |
五、yield冷门用法
| 1. send方法 :send方法是生成一些列结果的下一个元素 |
| |
| 通过调用send方法,将send的参数发送给 调用了next__方法产生了的生成器,并且生成器中的yield表达式返回了发送给send函数的值 |
| |
| def eat(name,food =None): |
| print(f'{name}准备吃饭') |
| while True: |
| food = yield |
| print(f'{name}准备吃{food}') |
| res = eat('jason') |
| res.__next__() |
| res.send('汉堡') |
| |
| |
| |
| |
| res.__next__() |
六、生成器表达式
1.生成器表达式
| 1.什么是生成器表达式:就是生成器的简化写法,结果是生成器对象 |
| ''' |
| 生成器里面的代码,只有 |
| 1 调用__next__方法 |
| 2 for循环的时候才会执行 |
| ''' |
| |
| l1 = (i ** 2 for i in range(100)) |
| print(l1) |
| |
| for i in l1: |
| print(i) |
| |
| |
| 2.生成器表达式是一个能够将函数的灵活性与推导语法的简洁性结合到一起的工具 |
| |
| def ups(line): |
| for i in line.split(','): |
| yield i.upper() |
| |
| |
| res = tuple(ups('aaa,bbb,ccc')) |
| print(res) |
| |
| d1 = {i: j for (i, j) in enumerate(ups('aaa,bbb,ccc'))} |
| print(d1) |
2.生成器表达式面试题
| |
| |
| 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) |
| |
| |
| |
| |
| |
| |
| 1.迭代对象和迭代器对象 |
| 1)迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器 |
| |
| 2.迭代器对象可以用 __next__方法不断获取迭代器的下一个值,如果没有下一个值了,就会抛出异常 StopIteration |
| |
| 3.for循环的本质,可以看作是不断的调用__next__ 方法获取下一个值来实现的 |
| |
| |
| 4.生成器可以看作是一个特殊的迭代器,生成器具有和迭代器一样的特性 |
| |
| 创建生成器的两种方法: 1)生成器表达式 2)生成器函数 |
| 1)生成器表达式 |
| |
| 生成器表达式和列表推导式差不多,我们只需要把列表推导式的[]改为(),列表推导式返回的结果是列表对象,生成器表达式返回的是一个生成器对象 |
| |
| 2)生成器函数 |
| |
| 普通函数用 return来返回值,生成器函数用 yield来返回值 |
| |
| |
| |
| 生成器函数和普通函数在执行流程上是有点区别的。 |
| |
| 对于普通函数,按顺序执行时遇到 return 或最后一行函数语句就会返回; |
| 对于有 yield的生成器函数,每次调用 __next__ 方法遇到 yield 语句才返回,如果再次调用 __next__ 方法,那么就会从上次返回的 yield 语句位置继续执行 |
| |
| 生成器还可以用于处理海量数据的场景,比如读取大文件时,如果直接一次性读取可能会导致内存溢出,这个时候我们就可以借助 yield 生成器来灵活控制读取,防止内存占用过大。 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY