python 生成器yield
来源:互联网 发布:北京飞秋网络 编辑:程序博客网 时间:2024/05/17 23:42
生成器概念
生成器是一次生成一个值的特殊类型函数
。可以将其视为可恢复函数。调用该函数将返回一个可用于生成连续 x 值的生成器。
包含yield关键字的函数可以理解是一个用函数名表示的另类list对象
,通过迭代的方式(例如:for)依次获取结果。
生成器的特点
- 记录执行函数内的所有变量状态(数据)和代码执行位置。
- 立即返回yield标记的变量或值,再次调用函数时,代码从上次返回yield之后继续执行。
认识生成器
下来让我们一起来看看如何使用yield,先通过一个简单的例子认识生成器。
def addlist(alist): for i in alist: # yield与return功能类似,返回本次迭代结果 yield i + 1alist = [1, 2, 3, 4]for x in addlist(alist): print(x)
执行结果:
2345
根据addlist()函数实现可以推断出addlist(alist)相当于一个值为[2, 3, 4, 5]的list,不过迭代调用时以函数表达式的形式出现在for语句中。
使用”list变量”(实际为函数变量,此处可以理解为list)替代addlist(alist)作为for的参数,执行结果相同,代码如下:
add_one_list = addlist(alist)for x in add_one_list: print(x)
生成器执行过程
到底yield是如何执行的呢?生成器(函数)的执行逻辑到底是什么样子?
让我们一起来写个demo进行分析。
next()函数
用于移动迭代器指向下一个数据,直到抛出StopIteration,代表迭代终止。
定义函数yield_run_logic(),对一个已经初始化变量a,多次调用,同在yield前后输出日志,用于分析执行逻辑。然后再一个while(1)的死循环中使用next()方法遍历生成器,直到抛出停止迭代异常跳出循环(StopIteration)。
def yield_run_logic(): a = 1 for i in range(3): print('begin yield') yield a print('end yield') a += i# 获取生成器对象yield_obj = yield_run_logic()# 此时只是获取对象,尚未执行yield_run_logic()的内容,直到第一调用next()\while 1: try: ret = next(yield_obj) # 第一次调用next()方法,开始执行yield_run_logic(),直到遇到yield关键字,返回当前结果, # yield_run_logic()保留当前执行状态和代码执行位置,当下次执行next()时, # yield_run_logic()从上次保留的继续执行,直到遇到yield关键字。 # yield_run_logic()无迭代数据时,抛出StopIteration异常,表示迭代结束。 print(ret) except StopIteration: print('end test') break
执行结果:
# 第1次执行输出 a = 1, i = 0begin yield1# 第2次执行输出 a = 1, i = 1end yieldbegin yield2# 第3次执行输出 a = 2, i = 2end yieldbegin yield4# 第4次执行end yield # yield_run_logic()中 i 超过range(3)的范围,结束迭代, # 由于使用next()而并非使用for来迭代生成器,所以迭代结束异常需要自己处理。end test
根据输出结果可以看出,在第一次执行next()时,生成器yield_run_logic()开始执行,打印’begin yield’,并在yield a
处返回结果,之后再执行next()都是从yield a
之后开始执行(打印’end yield’),直到循环中再次遇到yield a
时返回。
总结 yield的执行逻辑。
第一次获取迭代结果,函数的第一行代码执行到yield关键字返回,第[2,n]次迭代结果,函数执行从yield关键字下一行代码到再次碰到yield关键字返回。
yield的应用场景
凡是本次处理使用上次处理结果作为基础数据的逻辑实现,都可以考虑使用生成器。
练习1:打印杨辉三角
1 1 1 1 2 1 1 3 3 1 1 4 6 4 11 5 10 10 5 1
特征分析:从第三行开始每一行的非边界数字等于上一行相邻两数字之和,边界数字全部为1。
def pascals_triangle(line_count): up_line = [] line = [] # i取值范围[0, line_count-1] for i in range(line_count): # 扩展当前行列表长度,初始化数据为1,并且保证边界数据为1 line.append(1) # 1,2行全部是1,3行开始体现特征,需要进行特征处理 if i > 1: # 当前行[1, n-1]的值等于上一行[0, n-2]与[1, n-1]的和 for j in range(1, len(up_line)): line[j] = up_line[j-1] + up_line[j] # 返回当前行 yield line # 更新上一行记录结果,保存当前行 up_line = line[:]lines = 6fn = pascals_triangle(lines)for line in fn: print(line)
本例未将计算结果进行格式化输出,函数执行结果如下:
[1][1, 1][1, 2, 1][1, 3, 3, 1][1, 4, 6, 4, 1][1, 5, 10, 10, 5, 1]
资源链接
Python 深入理解yield
廖雪峰的python教程-生成器
[推荐阅读]Python Generators(生成器)——yield关键字
- python yield生成器
- Python yield 与生成器
- Python yield 生成器
- python生成器yield
- Python生成器-yield关键字
- python yield生成器
- python 生成器yield
- python 生成器yield
- 4. python生成器yield
- Python - yield 生成器
- python之生成器yield
- python yield生成器实验
- Python-迭代器、生成器、yield
- Python yield 生成器
- python-yield 生成器
- Python 迭代器 和 生成器yield
- Python生成器:yield的使用
- python中的生成器 generator yield
- 如何及时汇报反馈工作
- google breakpad
- MyBatis中SQL映射的XML文件
- PHP 八种基本的数据类型小结
- android AIDL 小结
- python 生成器yield
- 【java项目实战】代理模式(Proxy Pattern),静态代理 VS 动态代理
- java修饰符汇总
- Java 7新特性:自动化资源管理
- LeetCode - Nim Game
- Android界面的架构图
- 纯CSS菜单
- 数据库的基本操作(MySQL)
- 电子相册系统(六)相片列表显示