- 概述
生成器:按照程序员制定的规则,快速生成对象
特点:能提高编程效率,降低能耗
基础语法:生成器对象 = (生成器规则)
根据该语法格式,赋值生成器对象,直接打印时输出的是对象的地址,对此python中为了获取其内部的数据有两种API可供选择:
(1)通过for循环遍历获取所有数据
(2)通过next()逐次获取每个数据 - yield关键字的基础使用
# 定义一个简单函数,快速生成列表元素,存放到生成器中,并返回生成器对象 def func(): for i in range(5): yield [i,i+1] # 逐次存放列表元素到生成器中 if __name__ == '__main__': my_func = func() print(my_func) # 直接打印,为生成器对象的地址 # 法一 获取生成器中的所有元素 for data in my_func: print(data) # 法二 逐个获取生成器中的所有元素 for i in range(5): for data in next(my_func): print(data) """ 值得注意的是,法一执行后,再执行法二,会出现无数据的情况,这种情况与文件指针指向末尾类同 """
- 执行顺序
拿简单输出print为例,yield的执行顺序特殊在:逐次,具体如下:# 定义函数 def func(): for i in range(5): print(i) print('函数执行完毕') return func # main if __name__ == '__main__': my_func = func() # 赋函数返回值给my_func变量,同时执行函数中的输出语句
执行结果:
而改用yield对其稍加修改,如下:
# 定义函数 def func(): for i in range(5): yield i # 将元素i封装到生成器中 print(f'第{i + 1}次执行完毕') print('函数执行完毕') # main if __name__ == '__main__': my_generator = func() # 通过遍历获取全部数据 for data in my_generator: print(data)
执行结果如下:
可见,函数func调用赋值时,并未将其余两个print语句执行,反而在遍历获取所有数据时进行了打印输出。此时,我们再对主程序做下修改,更好的观察下,yield语句的执行顺序:
# 定义函数 def func(): for i in range(5): yield [i] # 将列表元素i封装到生成器中 print(f'第{i + 1}次执行完毕') print('函数执行完毕') # main if __name__ == '__main__': my_generator = func() # 利用next语句获取生成器中的第一个元素 print(next(my_generator)) print('-'*80) # 利用next语句获取生成器中的第二个元素 print(next(my_generator)) print('-'*80) # 利用next语句获取生成器中的第三个元素 print(next(my_generator)) print('-'*80) # 利用next语句获取生成器中的第四个元素 print(next(my_generator)) print('-'*80) # 利用next语句获取生成器中的第五个元素 print(next(my_generator)) print('-'*80) # 再使用一次next,会出现迭代错误 print(next(my_generator)) print('-'*80)
执行结果如下:
观测到的现象:
①函数中yield的封装是逐次的,不是一次性完成的,主程序每进行一次提取,相应的会提前进行一次封装
②循环提取时,由于封装也是循环的,故每封装一次,print(f'第{i+1}次执行完毕')
③当提取完最后元素再使用next时,程序会报错同时print('函数执行完毕')
结论:
yield与return类同,但不像return那么“霸道”,直接终止后续语句的执行