迭代器:
比方说一个数列,你将其遍历一遍就称之为迭代。这个数列就称之为迭代对象。迭代对象可以是字符可以是数列。
生成器:
数列的存储空间是有限的。如果数列的值可以通过算法来实现,那么这种通过算法来实现数列值的机制称之为"生成器(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循环随之结束。