生成器总结
生成器
1、生成器对象的本质
生成器对象其实本质上就是迭代器对象,内置有双下__ iter__ 和 __next __方法
2、区别
迭代器对象就是Python解释器提供的各种数据类型或是文件对象,但是生成器对象是程序员编写的代码或者函数之类的关键字。
3、生成器的两种形式
1.使用def定义函数然后内部使用yield关键字
在使用函数+yield关键字定义生成器的时候需要注意当我们使用括号调用函数的时候并没有运行这个函数,而是把这个函数体代码变成了一个生成器对象,之后我们想要调用函数产生数据就需要跟迭代器一样使用 __ next __方法,并且每次运行的时候如果遇到yield关键字就会停止到那个位置,如果下方代码还有yield关键字,下一次运行双下划线的next方法就会运行到下一个yield关键字处停止。
def my_iter(): print('哈哈哈 椰子汁很好喝') yield ''' 1.函数体代码中如果有yield关键字 那么函数名加括号并不会执行函数体代码 会生成一个生成器对象(迭代器对象) ''' res = my_iter() print(res) '''2.使用加括号之后的结果调用__next__才会执行函数体代码''' res.__next__() # <generator object my_iter at 0x000002161040A900> # 哈哈哈 椰子汁很好喝
下面是多个yield的使用场景:
'''3.每次执行完__ next __ 代码都会停在yield位置 下次基于该位置继续往下找第二个yield''' def my_iter(): print('哈哈哈 椰子汁很好喝') yield 111, 222, 333. print('呵呵呵 从小喝到大') yield 111, 222, 333 print('嘿嘿嘿 特种兵牌还可以') yield 111, 222, 333 print('哼哼哼 千万别整多了 倒沫子 头发掉光光') yield 111, 222, 333
注:在上面的代码运行过程中我们也发现了yield关键字跟return一样可以返回返回值
2.使用生成器表达式
可以简化代码,节省内存
l1 = (i ** 2 for i in rang(100)) # 生成器对象 print(l1) for i in l1: print(i)
使用生成器生成对象后需要使用循环输出里面的数据值,或者转换类型后一次性输出
3、自定义生成器对标range功能(一个参数 两个参数 三个参数 迭代器对象)
考虑到range功能复杂,所以我们这里要使用函数加yield关键字的方法来简历自定义生成器
def my_range(start_num, end_num=None, step=1): # 判断end_num是否有值 没有值说明用户只给了一个值 起始数字应该是0 终止位置应该是传的值 is_back = False if not end_num: # 判断第二个结束为止是否有参数,如果没有就把传给起始位置的参数给结束为止,其实位置变成0 end_num = start_num start_num = 0 if step == 0: yield '位移量不能为0' if step < 0: # 判断取值的步频是否为反方向 # 如果是反方向的步频,判断起始位置和结束为止是否前面的大后面的小 if not start_num > end_num: yield '参数大小错误' else: is_back = True # 起始位置和结束为止是前面的大后面的小的时候就返回True while start_num < end_num or is_back: # 起始位置小于结束位置的时候或是步频为负数的时候判断正确的话就输出数据值 if start_num < end_num: # 起始位置小于结束位置 print(start_num) yield start_num start_num += step elif is_back: # 步频为负数 if start_num > end_num: yield start_num start_num += step else: is_back = False # 定义了模仿range方法的功能后,用for循环的方式调用内部数据值 for i in my_range(100, 50, 0): print(i)
二、yield冷门用法
当我们使用yield关键字的时候可以用变量名绑定yield关键字,然后就可以使用send方法传参,然后会再次运行到yield关键字处停止运行
def eat(name, food=None): print(f'{name}准备用餐') while True: food = yield print(f'{name}正在吃{food}') res = eat('jason') res.__next__() res.send('汉堡') # 1.将括号内的数据传给yield前面的变量名 2.再自动调用__next__ res.send('包子') res.send('面条') ''' jason准备用餐 jason正在吃汉堡 jason正在吃包子 jason正在吃面条 '''
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构