python生成器

  通过列表生成式,我们可以直接创建一个列表,但是收到内存限制,列表容量是有限的。而且创建一个包含100万个元素的列表未免太占用空间了,如果我们只需要访问前面的几个元素,那多出来的空间就被白白浪费掉了。所以如何只生成前几个元素呢?

  所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。

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

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

  我们可以通过下标打印出,list的每个元素,那么怎么打印生成器对应的元素呢?

  如果要一个一个打印,可以使用next()方法。next(g)

  不过我们一般使用for循环:

  

  生成器的两种形式(Python有两种不同的方式提供生成器)  

  1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。生成器和函数的执行流程不一样,函数是顺序执行,遇到return语句或者最后一行函数语句就结束。在调用生成器运行过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield值。并在下一次执行next方法时,从当前位置继续运行。

  yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator。

  下面为一个可以无穷生产奇数的生成器函数。(可以看出使用生成器是十分方便的)

  

def odd():
    n=1
    while True:
        yield n
        n+=2
odd_num = odd()
count = 0
for o in odd_num:
    if count >=5: break
    print(o)
    count +=1

  

  2、生成器表达式:类似于列表推导,但,生成器返回按需生产结果的一个对象,而不是一次构建一个结果列表。

  

g = (i for i in range(10**100))#生成器表达式
L = [i for i in range(10**100)]#列表生成式

  一个小例子

  斐波那契数列的实现,虽然它无法使用列表推导式打印出来,但是用函数可以轻易的打印出来

  

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

  怎么能用生成器的方法来实现呢?只需把return改成yield就好。

  

 def fib(max):
     n, a, b = 0, 0, 1
     while n < max:
         yield b
         a, b = b, a + b
         n = n + 1
 In [67]: fib(6)
 Out[67]: <generator object fib at 0x000000000484BD58>
 
 In [68]: a = fib(6)
 
 In [69]: next(a)
 Out[69]: 1
 
 In [70]: next(a)
  Out[70]: 1
 
  In [71]:

  当我们调用fib(6)的时候,提示这是一个generator对象。是不能这么打印的。

  

原文地址:https://www.cnblogs.com/happyfool/p/8576018.html