生成器

迭代器:

比方说一个数列,你将其遍历一遍就称之为迭代。这个数列就称之为迭代对象。迭代对象可以是字符可以是数列。

生成器:  

 
数列的存储空间是有限的。如果数列的值可以通过算法来实现,那么这种通过算法来实现数列值的机制称之为"生成器(Generator)"

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

1 >>> L = [x * x for x in range(10)]
2 >>> L
3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4 >>> g = (x * x for x in range(10))
5 >>> g
6 <generator object <genexpr> at 0x104feab40>

来源: https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00138681965108490cb4c13182e472f8d87830f13be6e88000
如何使用直接使用next()即可

 1 >>> l.next()
 2 0
 3 >>> l.next()
 4 1
 5 >>> l.next()
 6 4
 7 >>> l.next()
 8 9
 9 >>> l.next()
10 16
11 >>> l.next()
12 25
13 >>> l.next()
14 36
15 >>> l.next()
16 49
17 >>> l.next()
18 64
19 >>> l.next()
20 81
21 >>> l.next()
22 Traceback (most recent call last):
23 File "<stdin>", line 1, in <module>
24 StopIteration

当没有的时候就会抛出StopIteraction错误
我们创建了一个generator后,基本上永远不会调用next()方法,而是通过for循环来迭代它

 1 >>> s = (x*x for x in range(10))
 2 >>> for i in s:
 3 ...     print i
 4 ...
 5 0
 6 1
 7 4
 8 9
 9 16
10 25
11 36
12 49
13 64
14 81

用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

1 def fib(max):
2    n, a, b = 0, 0, 1
3    while n < max:
4        print b
5        a, b = b, a + b
6        n = n + 1

上面的函数可以输出斐波那契数列的前N个数:

1 >>> fib(6)
2 1
3 1
4 2
5 3
6 5
7 8

仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print b改为yield b就可以了:

1 def fib(max):
2 n, a, b = 0, 0, 1
3 while n < max:
4 yield b
5 a, b = b, a + b
6 n = n + 1

#个人认识好像就等同于print没区别似的

1 >>> def fib(max):
2 ...    n,a,b = 0,0,1
3 ...    while n < max:
4 ...            yield b
5 ...            a,b = b,a+b
6 ...            n +=1
7 ...
8 >>> fib(6)
9 <generator object fib at 0x00B73670>

        这里,最难理解的就是generator和函数的执行流程不一样

        函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。



举个简单的例子,定义一个generator,依次返回数字1,3,5:

 1 >>> def odd():
 2 ... print 'step 1'
 3 ... yield 1
 4 ... print 'step 2'
 5 ... yield 3
 6 ... print 'step 3'
 7 ... yield 5
 8 ...
 9 >>> o = odd()
10 >>> o.next()
11 step 1
12 1
13 >>> o.next()
14 step 2
15 3
16 >>> o.next()
17 step 3
18 5
19 >>> o.next()
20 Traceback (most recent call last):
21 File "<stdin>", line 1, in <module>
22 StopIteration

可以看到,odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next()就报错。

回到fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。

同样的,把函数改成generator后,我们基本上从来不会用next()来调用它,而是直接使用for循环来迭代:

1 >>> for n in fib(6):
2 ... print n
3 ...
4 1
5 1
6 2
7 3
8 5
9 8

小结

generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。

要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

原文地址:https://www.cnblogs.com/nul1/p/8904335.html