利用迭代器,咱们能够在每次迭代获取数据(经过next()方法)时按照特定的规律进行生成。可是咱们在实现一个迭代器时,关于当前迭代到的状态须要咱们本身记录,进而才能根据当前状态生成下一个数据。
为了达到记录当前状态,并配合next()函数进行迭代使用,咱们能够采用更简便的语法,即生成器(generator)。生成器是一类特殊的迭代器。
python
要建立一个生成器,有不少种方法。第一种方法很简单,只要把一个列表生成式的 [ ] 改为 ( )算法
>>> L = [x**2 for x in range(5)] >>> L [0, 1, 4, 9, 16] >>> G = (x**2 for x in range(5)) >>> G <generator object <genexpr> at 0x7fb63d218750>
建立 L 和 G 的区别仅在于最外层的 [ ] 和 ( ) , L 是一个列表,而 G 是一个生成器。咱们能够直接打印出列表L的每个元素,而对于生成器G,咱们能够按照迭代器的使用方法来使用,便可以经过next()函数、for循环、list()等方法使用。shell
>>> next(G) 0 >>> next(G) 1 >>> next(G) 4 >>> next(G) 9 >>> next(G) 16 >>> next(G) Traceback (most recent call last): File "<pyshell#39>", line 1, in <module> next(G) StopIteration >>> G = ( x**2 for x in range(5)) >>> for x in G: print(x)
generator很是强大。若是推算的算法比较复杂,用相似列表生成式的 for 循环没法实现的时候,还能够用函数来实现。
就像以前提到的斐波那切数列
函数
注意,在用迭代器实现的方式中,咱们要借助几个变量(n、current、num一、num2)来保存迭代的状态。如今咱们用生成器来实现一下。3d
>>> def fib(n): current = 0 num1, num2 = 0, 1 while current < n: num = num1 num1, num2 = num2, num1 + num2 current += 1 yield num return '完成' >>> F = fib(5) >>> next(F) 0 >>> next(F) 1 >>> next(F) 1 >>> next(F) 2 >>> next(F) 3 >>> next(F) Traceback (most recent call last): File "<pyshell#80>", line 1, in <module> next(F) StopIteration: 完成
在使用生成器实现的方式中,咱们将本来在迭代器__next__
方法中实现的基本逻辑放到一个函数中来实现,可是将每次迭代返回数值的return换成了yield,此时新定义的函数便再也不是函数,而是一个生成器了。
简单来讲:只要在def中有yield关键字的 就称为 生成器
此时按照调用函数的方式( 案例中为F = fib(5) )使用生成器就再也不是执行函数体了,而是会返回一个生成器对象( 案例中为F ),而后就能够按照使用迭代器的方式来使用生成器了。code
>>> for n in fib(5): print(n) 0 1 1 2 3 >>>
可是用for循环调用generator时,发现拿不到generator的return语句的返回值。若是想要拿到返回值,必须捕获StopIteration
错误,返回值包含在StopIteration的value中:对象
>>> g = fib(5) >>> while True: try: x = next(g) print(f"value:{x}") except StopIteration as e: print(f"生成器返回值:{e.value}") break value:0 value:1 value:1 value:2 value:3 生成器返回值:完成
生成器
。(使用了yield的函数就是生成器)next()
函数让生成器从断点处继续执行,即唤醒生成器(函数)咱们除了可使用next()
函数来唤醒生成器继续执行外,还可使用send()
函数来唤醒执行。使用send()函数的一个好处是能够在唤醒的同时向断点处传入一个附加数据。
例子:执行到yield时,gen函数做用暂时保存,返回i的值; temp接收下次c.send("python")
,send发送过来的值,c.next()等价c.send(None)generator
>>> def gen(): i = 0 while i < 5: temp = yield i print(temp) i += 1
>>> f = gen() >>> next(f) 0 >>> f.send('haha') haha 1 >>> next(f) None 2 >>> f.send('haha') haha 3 >>>