Chinaunix首页 | 论坛 | 博客
  • 博客访问: 438686
  • 博文数量: 26
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1101
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-04 22:28
个人简介

Never stop learning.

文章分类

全部博文(26)

文章存档

2014年(2)

2013年(24)

分类: Python/Ruby

2013-11-19 23:22:48

【Python那些事儿之八】Generators详解

by Harrison Feng in Python

生成器(Generator)在计算机科学中是用于控制循环迭代行为的一种特殊程序。简单的讲,它其实就是一个特别
函数。在Python里,生成器是一个返回迭代器的函数。它与普通函数的区别就在于它包含一个yield语句。而yield

句本身也只用于定义生成器。yield语句生成的是一个序列(一系列值)。这些值可以通过生成器对象的next()方法

个一个返回。直到所有的值都返回完后,StopIteration的异常会被抛出。请看下面的代码:

  1. def count_down(i):
  2.     print "Let's count down from %d" % i
  3.     while i > 0:
  4.         yield i
  5.         i -= 1
这里定义一个简单的生成器。而下面的实验则展示了生成器的特性。
  1. >>> dcnt = count_down(5) # 调用生成器。
    >>> dcnt
    # 生成器对象。
    >>> dcnt.next()
    Let's count down from 5
    5
    >>> dcnt.next()
    4
    >>> dcnt.next()
    3
    >>> dcnt.next()
    2
    >>> dcnt.next()
    1
    >>> dcnt.next()                    # 所有的值都生成完后,StopIteration异常抛出。
    Traceback (most recent call last):
      File "", line 1, in
    StopIteration
    >>>
从上面的代码我们可以看出,生成器函数在被调用时并不会运行,而是当调用生气器对象的next()方法时,它
才会开始运行。而且next()返回的都是下一个值,直到所有的值都被返回完毕。其实yield语句在生成一个值后
(next()方法被调用时),它会暂停生成器函数,并记住当前的状态。当再次调用next()方法时,生成器函数被
恢复,继续生成下一个值,以此类推。上面的这个实验很好的展示了生成器的这一特性。
生成器函数提供了一种更便利的方式来创建迭代器(Iterator),而且不用关心迭代协议。生成器是一次性操作,
只能在生成器对象上完整遍历一次。如果还需要遍历,则需要重新调用生成器函数。
  1. >>> dcnt = count_down(3)
    >>> for i in dcnt:
    ...     print i
    ...
    Let's count down from 3
    3
    2
    1
    >>> for i in dcnt:
    ...     print i
    ...
    >>>
  2. >>> dcnt = count_down(3)
    >>> for i in dcnt:
    ...     print i
    ...
    Let's count down from 3
    3
    2
    1
    >>>
上面的实验看出,在第二次遍历生成器对象时,没有任何输出。重新创建生成器对象后则可继续遍历。
在Python里,还有一种特殊的表达式,生成器表达式(Generator Expression)。一般情况下,如果一个
表达式返回的是一个迭代器(iterator),它就是生成器表达式(Generator Expression)。
最简单的生成器表达式:
  1. >>> gx = (x ** 2 for x in xrange(10))
  2. >>> gx
  3. <generator object <genexpr> at 0x7f0cf1f254b0>
  4. >>>
从上面的代码可以看出,生成器表达式和生成器函数相似,都能创建生成器对象,从而实现遍历操作。
生成器表达式的通用语法:
  1. (expression for i in s1 if cond1
  2.             for j in s2 if cond2
  3.             ...
  4.             if condfinal)
相当于
  1. for i in s1:
  2.         if cond1:
  3.             for j in s2:
  4.                 if cond2:
  5.                     ...
  6.                     if condfinal: yield expression
是不是感觉生成器表达式就是生成器函数的变体?其实可以这么理解。
最后,我们可以总结一下生成器的特性:
1)
必须包含yield语句的函数。
2)在调用时不会运行。
3)调用生成器时生成的生成器对象只能被使用一次(遍历)。
4)返回迭代器,但是不用关心迭代协议。

by Harrison Feng in Python
阅读(5311) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~