深入浅出学习Python的yield和generator
2018-03-21 19:19
736 查看
背景
之前走马观花接触过Python协程的概念,这两天和一个同事聊到了协程,死活想不起来曾经看过的东西,就记得一个yield,概念不清;所以想捋一捋相关的东西,此篇作为学习的记录。
Generator
generator(生成器)保存的是算法,可以理解为一个特殊的函数,有迭代(可迭代的对象都有一个__next()__成员方法)的属性
可以被用作控制循环的迭代行为,做到一边循环一边计算;特点是只有被调用的的时候才会生成,能做到不多占用系统的资源。
在我们日常工作过程中接触最多的generator可能就是Python3.X中的range函数,我们来看一下它和Python2.x中range的用法区别:
# python2 >>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> type(range(10)) <type 'list'> # python3 >>> range(10) range(0, 10) >>> type(range(10)) <class 'range'> >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
如示例,Python2 是直接生成的列表list,而Python3中调用range(10)实际上是生成了一个range类,需要转换才能生成list。
Python2这样直接生成列表的机制,在实际使用中容量可能会受到内存的限制。而且如果创建一个包含100万个元素的列表,而我们又仅仅只需要访问前面几个元素,那绝大多数的内存占用就会白白浪费。所以Python3的开发者们才会在这一个小小的函数上下这么大的功夫。
Generator的使用
创建generator:列表生成式
创建generator方法有很多,最直接最简单的方法就是使用 列表生成式:>>> L = [x * 2 for x in range(5)] >>> L [0, 2, 4, 6, 8] >>> G = (x * 2 for x in range(5)) >>> G <generator object <genexpr> at 0x000000000309DD58>
如上例,只要把一个列表生成式的
[]改成
(),就创建了一个generator
我们可以通过
next()函数获得generator的返回值
>>> next(G) 0 >>> next(G) 2 >>> next(G) 4 >>> next(G) 6 >>> next(G) 8 >>> next(G) Traceback (most recent call last): File "<pyshell#16>", line 1, in <module> next(G) StopIteration
每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
当然,这个只是测试,正确的使用方式是使用for循环,
在for循环中,会自动遵循迭代规则,每次调用next()函数,而且不需要关心StopIteration的错误。
>>> for i in G: print(i) 0 2 4 6 8
创建generator: 直接定义生成器函数
# 普通函数 def commom_func(max): print("create counter") counter = 0 while counter < max: print(counter) print('counter increase') counter += 1 # 生成器函数 def yield_func(max): print("create counter") counter = 0 while counter < max: yield counter print('counter increase') counter += 1 # 生成器函数调用 if __name__ == '__main__': num = yield_func(5) print(next(num)) print(next(num)) print(next(num))
--- # 生成器函数调用输出 create counter 0 counter increase 1 counter increase 2
从上面这个例子可以看出以下几点:
在yield_func函数中出现了关键字yield,这个函数返回一个生成器(通过第一行输出可以看出来),用来产生连续的n值,生成器每次只产生一个结果值
在创造生成器实例的时候,只需要像普通函数一样调用就可以,但是这个调用却不会执行这个函数
next()函数将生成器对象作为自己的参数,在第一次调用的时候,他执行了yield_func函数到yield语句,返回产生的值0
我们重复的调用next()函数,每次他都会从上次被挂起的地方开始执行,直到再次遇到了yield关键字
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
下面是一个更直观的例子
def step_test(): print('step 1') yield 1 print('step 2') yield 2 print('step 3') yield 3
调用该generator时,
首先要生成一个generator对象,然后用next()函数不断获得下一个返回值:
>>> test = step_test() >>> next(test) step 1 1 >>> next(test) step 2 2 >>> next(test) step 3 3
总结
generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。
普通函数调用直接返回结果,generator函数的“调用”实际返回一个generator对象:
>>> step_test() <generator object step_test at 0x0000000001DE5B48>
相关文章推荐
- evenlet引发的学习-python 'yield'以及'generator'
- 深入学习python的yield和generator
- 深入学习python的yield和generator
- python学习笔记之yield
- python yield的初识,Iterator与Generator
- python yield函数深入浅出理解
- [python学习]利用generator实现杨辉三角
- python yield生成器 分类: python基础学习 2013-08-04 15:40 324人阅读 评论(0) 收藏
- python yield和generator
- python yield generator 详解
- python generator / yield statement
- python学习笔记-Day04-第三部分(内置函数,map,filter,reduce,yield)
- python学习 - yield
- python yield学习心得
- python3----生成器generator(yield)
- Python yield关键字 和 Generator(生成器)
- Python 中的yield 以及 generator
- python yield generator 详解
- 08-python学习笔记-生成器:generator
- Python中request模块学习【深入浅出】