python generator

生成器是python中一个非常酷的特性,python 2.2中引入后在2.3变成了标准的一部分。它能够让你在许多情况下以一种优雅而又更低内存消耗的方式简化无界(无限)序列相关的操作。

生成器是可以当做iterator使用的特殊函数,它功能的实现依赖于关键字yield,下面是它如何运作一个简单的演示:

复制代码
>>>def spam():
yield"first"
yield"second"
yield"third"


>>> spam
<function spam at 0x011F32B0>
>>>for x in spam():
print x


first
second
third
>>> gen=spam()
>>> gen
<generator object spam at 0x01220B20>
>>> gen.next()
'first'
>>> gen.next()
'second'
>>> gen.next()
'third'
复制代码

在函数spam()内定义了一个生成器,但是对spam()的调用永远只能获得一个单独的生成器对象,而不是执行函数里面的语句,这个对象(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异常

一个经典的例子是和C语言中的static语句相比较:在Python没有明确支持的所谓static变量,但是在函数之间相互调用时,生成器能让你能以一个更优雅的方式实现类似的效果:

在C语言中  fibonacci 函数的实现:

复制代码
#include <stdio.h>

int main() {
printf(
"0\n");
printf(
"1\n");
while (1)
printf(
"%d\n",fib());
/* for test use*/
// int i=0;
// while(i<20){
// i++;
// printf("%d\n", fib());}
}

int fib() {
static unsigned first=0,second=1,next,retval;

next
=first+second;
retval
=next;
first
=second;
second
=next;

return retval;

}
复制代码

python实现:

复制代码
#!/usr/bin/env python 
#
 -*- coding: utf-8 -*- 
#
 filename: fib.py

def fib():
first
=0
second
=1
yield first
yield second

while1:
next
=first+second
yield next
first
=second
second
=next
复制代码

运行:

复制代码
>>>from fib import fib
>>> fib()
<generator object fib at 0xb76fcfcc>
>>>import itertools
>>> list(itertools.islice(fib(), 10))
[0, 
112358132134]
复制代码

也可以用如下方式截取一部分输出(但建议使用 itemtools 模块):

>>>for (i, num) in zip(range(10),fib()):
... 
print num

上述 fibonacci 函数的实现看起来较为繁琐,更加简捷优雅的实现如下:

复制代码
#!/usr/bin/env python 
#
 -*- coding: utf-8 -*- 
#
 filename: fib.py

def fib():
first, second
=0, 1
while1:
yield second
first, second
= second, first+second
复制代码

注意:但是在C语言中由于static的特性,在一个函数体内当需要产生多组 fibonacci 数列时可能就需要定义相同的诸如fib1() fib2() fib3()的函数。python中可以利用上述函数构造任意多个独立的生成器对象。

至于生成器(generator)应该使用在哪些方面以便更好地节省内存——你可以使用在需要计算列表的值但是每次只需要访问一个item的地方,和预先计算好将其存储在一个列表里相比,生成器在运行中逐个计算其值(computes the values on the fly)。

转载请注明出处:http://www.cnblogs.com/moinmoin/


关于itertools.islice()说明:
itertools. islice ( iterablestop ) itertools. islice ( iterablestartstop [step ] )

Make an iterator that returns selected elements from the iterable. If start is non-zero, then elements from the iterable are skipped until start is reached. Afterward, elements are returned consecutively unless step is set higher than one which results in items being skipped. If stop is None, then iteration continues until the iterator is exhausted, if at all; otherwise, it stops at the specified position. Unlike regular slicing, islice() does not support negative values for startstop, or step. Can be used to extract related fields from data where the internal structure has been flattened (for example, a multi-line report may list a name field on every third line). Equivalent to:

def islice(iterable, *args):
    # islice('ABCDEFG', 2) --> A B
    # islice('ABCDEFG', 2, 4) --> C D
    # islice('ABCDEFG', 2, None) --> C D E F G
    # islice('ABCDEFG', 0, None, 2) --> A C E G
    s = slice(*args)
    it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1))
    nexti = next(it)
    for i, element in enumerate(iterable):
        if i == nexti:
            yield element
            nexti = next(it)

If start is None, then iteration starts at zero. If step is None, then the step defaults to one.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值