生成器,生成器表达式。

今天在看python的时候接触到了生成器和生成器表达式的概念,感觉有点迷糊。特此总结记忆一下。

生成器的出现可以说是基于下面一种需求。首先,我们来看一端python程序。

[root@racnode1 tmp]# cat /tmp/test
aaaaa
bbbbbbbbb
ccccc
ddddd
[root@racnode1 tmp]# python
Python 2.6.6 (r266:84292, Dec 20 2012, 15:52:58)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open('/tmp/test')
>>> allLineLens=[len(x.strip())  for x in f]
>>> f.close()
>>> max(allLineLens)
9

首先我们看到一个很简单的文件/tmp/test 共有四行,第二行最长有9个字符。 然后我们用一段python程序来检测该文件最长的行长度是多少。

f=open('/tmp/test')是打开这个文件。

allLineLens=[len(x.strip())  for x in f] 是通过一个列表解析来获得一个列表。该列表中的每一个元素都是f中每一行的长度

f.close()是关闭文件

max(allLineLens)是找出该列表中最大的值。

这段程序清晰明了,但是有一个问题,如果这个文件非常大,那么我们要得到的列表可能就会非常大。这样会占用内存很大。这里我们就可以用到生成器表达式来解决这个问题。生成器表达式的语法和列表表达式一样。只是不用[],而且它生成的不是列表而是一个生成器。什么是生成器我们稍后解释。

列表解析:
[expr for iter_var in iterable if cond_expr]
生成器表达式:
(expr for iter_var in iterable if cond_expr)

上面的例子用生成器表达式来改写就是:

>>> f = open('/tmp/test')
>>> max( len(x.strip()) for x in f)
9

这段代码与上面的区别是 len(x.strip()) for x in f返回的不是一个列表而是一个生成器对象。生成器占用内存非常小。所以就解决了我们之前列表占用内存过大的问题。

那么生成器是什么呢? 

生成器是一次生成一个值的特殊类型函数。可以将其视为可恢复函数。调用该函数将返回一个可用于生成连续 x 值的生成器【Generator】

简单的说就是在函数的执行过程中,yield语句会把你需要的值返回给调用生成器的地方,然后退出函数,下一次调用生成器函数的时候又从上次中断的地方开始执行,而生成器内的所有变量参数都会被保存下来供下一次使用。

  1. >>> def fib(max):  
  2.     a, b = 01            
  3.     while a < max:  
  4.         yield a            
  5.         a, b = b, a + b  
  6.   
  7.       
  8. >>> for i in fib(1000):  
  9.     print(i)  
  10.   
  11.       
  12. 0  
  13. 1  
  14. 1  
  15. 2  
  16. 3  
  17. 5  
  18. 8  
  19. 13  
  20. 21  
  21. 34  
  22. 55  
  23. 89  
  24. 144  
  25. 233  
  26. 377  
  27. 610  
  28. 987  
  29.   
  30. >>>f = fib(1000)  
  31. >>>f.next()            #python 3.0 要写成f.__next__()  否则出错  
  32. 0  
  33. >>>f.next()  
  34. 1  
  35. >>>f.next()  
  36. 1  
  37. >>>f.next()  
  38. 2  

#python 3.0 要写成f.__next__()  否则出错  AttributeError: 'generator' object has no attribute 'next'

在函数fib(max)内定义了一个生成器,但是对fib(max)的调用永远只能获得一个单独的生成器对象,而不是执行函数里面的语句,这个对象(generator object)包含了函数的原始代码和函数调用的状态,这状态包括函数中变量值以及当前的执行点——函数在yield语句处暂停(suspended),返回当前的值并储存函数的调用状态,当需要下一个条目(item)时,可以再次调用next,从函数上次停止的状态继续执行,知道下一个yield语句。

生成器和函数的主要区别在于函数 return a value,生成器 yield a value同时标记或记忆 point of the yield 以便于在下次调用时从标记点恢复执行。 yield 使函数转换成生成器,而生成器反过来又返回迭代器。

有三种方式告诉循环生成器中没有更多的内容:

  1. 执行到函数的末尾("fall off the end")
  2. 用一个return语句(它可能不会返回任何值)
  3. 抛出StopIteration异常

总的来说生成器是一类特殊 迭代器。 一个产生值的函数 yield 是一种产生一个迭代器却不需要构建迭代器的精密小巧的方法

原文地址:https://www.cnblogs.com/kramer/p/3544591.html