Python入门之生成器
Python生成器
什么是python生成器(generator),意思是带有一个yield语句的函数,既然它是个函数,那么与普通的函数有什么关系呢?
生成器是这样一个函数:记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置
生成器的特点:
生成器是一个函数,而且函数的参数都会保留。
迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
yield 生成器的运行机制:
当你问生成器要一个数时,生成器会执行,直至出现 yield 语句,生成器把 yield 的参数给你,之后生成器就不会往下继续运行。 当你问他要下一个数时,他会从上次的状态。开始运行,直至出现yield语句,把参数给你,之后停下。如此反复直至退出函数。
生成器2种创建方式:
1.第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
#!/usr/bin/env python3 l = [i for i in range(10)] print(l,"类型:",type(l)) g = (i for i in range(10)) print(g,"类型:",type(g)) 执行结果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 类型: <class 'list'> <generator object <genexpr> at 0x7f878b79b4c0> 类型: <class 'generator'>
1.1上面可以看出,列表元素我们可以直接打印出来,那生成器的元素怎么取出呢?其实我们可以通过next()方法一个一个按顺序取出;直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
#!/usr/bin/env python3 g = (i for i in range(10)) print(g,"类型:",type(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g) 执行结果: <generator object <genexpr> at 0x7fe9b64524c0> 类型: <class 'generator'> 0 1 2 3 4 5 6 7 8 9 Traceback (most recent call last): File "./pytest22.py", line 18, in <module> print(next(g)) StopIteration
1.2当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象;在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作:
#!/usr/bin/env python3 g = (i for i in range(10)) print(g,"类型:",type(g)) for i in g: print(i) 执行结果: <generator object <genexpr> at 0x7fdf625084c0> 类型: <class 'generator'> 0 1 2 3 4 5 6 7 8 9
2.如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
#!/usr/bin/env python3 def odd(): print("yields num: 1") yield 1 print("yields num: 2") yield 2 print("yields num: 3") yield 3 o = odd() print(next(o)) print(next(o)) print(next(o)) print(next(o)) 执行结果: yields num: 1 1 #yield 1 yields num: 2 2 #yield 2 yields num: 3 3 #yield 3 Traceback (most recent call last): File "./pytest21.py", line 16, in <module> print(next(o)) StopIteration #生成器元素去完
可以看到,odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next(o)就报错。
参考:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317799226173f45ce40636141b6abc8424e12b5fb27000
http://www.cnblogs.com/hustcser/p/4256177.html

浙公网安备 33010602011771号