python 生成器(generator)浅析

python struggling 857次浏览 0个评论
In [2]: [ x*x for x in range(10) ] 
Out[2]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

In [7]: a = ( x*x for x in range(10) )

In [8]: a
Out[8]: <generator object <genexpr> at 0x7f716a282fa0>

In [9]: a.next()
Out[9]: 0

In [10]: a.next()
Out[10]: 1

In [11]: a.next()
Out[11]: 4

In [12]: a.next()
Out[12]: 9

首先看上面的例子,发现什么不同没?使用 [] 推导出来的是列表,而使用 ()推导出来的是生成器。

可以看出,生成器是一个可迭代对象,它不会一次性给你返回所有的值,而是当你问生成器要一个值时,生成器才会返回一个值,这是最简单的理解。

在 python 中,由于受到内存限制,列表容量不可能无限大,而且,我们也不可能一次性访问那么大的列表,所以,大多时候我们都是按需访问,只访问前面几个元素,因此,像生成器这种一边循环一边计算的才是高效的。


生成器的特点:

生成器是一个函数,并且会保留函数参数的值。

当迭代到下一次的调用时,所使用参数的值都是上一次计算后所保留下的,相当于每次会像创建快照一样保存上一次迭代的执行结果,当在下一次调用时,就会使用上一次的结果,而不是新创建的。


在Python中,yield 就是这样的一个生成器。

先看 yield 的一个例子:

In [61]: def frange(start,stop,increment=1):
   ....:     x = start
   ....:     while x < stop : 
   ....:         yield x 
   ....:         x += increment
   ....:         

In [62]: for n in frange(1,4):
   ....:     print n
   ....:     
1
2
3

此函数就是一个生成器,生成器是特殊的迭代器,通过 for 来访问函数中的可迭代对象,函数每次只返回一个值,即运行到 yield 处就会暂停,然后返回一个包含当前函数所有参数的状态的iterator对象,当程序请求下一个值时,此时便从前面所执行到的步骤处继续执行,当执行到 yield 处又会暂停,一直循环下去,直到执行完。注意: yield 不能与 return 一起连用。

深入理解 yield 机制:

In [63]: def countdown(n):
   ....:     print 'start-->',n
   ....:     while n > 0:
   ....:         yield n
   ....:         n -= 1
   ....:     print 'done'
   ....:     

In [64]: c = countdown(3) 

#创建一个生成器

In [65]: c
Out[65]: <generator object countdown at 0x7fb3eb60fb40>

In [66]: c.next()
start--> 3
Out[66]: 3

#程序先执行第一条 print 语句,然后执行 while 中的语句,当执行到 yield 时便暂停,此时函数保存执行中的所有状态然后返回一个 iterator 对象

In [67]: c.next()
Out[67]: 2

#当请求下一个数时,此时程序继续上一次执行的状态,当执行到 yield 时又处于暂停状态,返回一个 iterator 对象

<pre class="prettyprint linenums" >
In [68]: c.next()
Out[68]: 1

#运行最后一个 yield

In [69]: c.next()
done
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-69-50b4dad19337> in <module>()
----> 1 c.next()

StopIteration: 

此时程序已执行完毕。

生成器函数只会在响应迭代过程中的‘next’操作时才会运行,一旦生成器函数返回,迭代也就停止了,通常 for 语句替我们处理迭代过程。


实现生成器的三种方式:

1. t = (i for i in range(10))

2. 使用 yield

3. 实现 __iter__ 和 next 方法


以下为实现 __iter__ 和 next 方法:

In [29]: class Fib():
    def __init__(self):
        self.num1 = 0
        self.num2 = 1
    def __iter__(self):
        return self
    def next(self):
        if self.num2 < 10:
            self.num1,self.num2 = self.num2,self.num1 + self.num2
            return self.num2
        else :
            raise StopIteration
   ....:         

In [30]: fib = Fib()

In [31]: fib
Out[31]: <__main__.Fib instance at 0x7f7dbf4a0b90>

In [32]: fib.next()
Out[32]: 1

In [33]: fib.next()
Out[33]: 2

In [34]: for i in fib:
   ....:     print i
   ....:     
3
5
8
13

DevOps-田飞雨 》》转载请注明源地址
喜欢 (2)or分享 (0)
发表我的评论
取消评论
*

表情 贴图 加粗 链接 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址