迭代器与生成器

迭代器(iterator)

iterator: 迭代器对象,也属于python的名词,只能迭代一次。需要满足如下的迭代器协议

  • 定义了__iter__方法,但是必须返回自身

  • 定义了next方法,在python3.x是__next__用来返回下一个值,并且当没有数据了,抛出StopIteration

  • 可以保持当前的状态

自定义iterator 与数据分离

说到这里,迭代器对象基本出来了。下面大致说一下,如何让自定义的类的对象成为迭代器对象,其实就是定义__iter__next方法:

In [1]: %paste
class DataIter(object):

    def __init__(self, *args):
        self.data = list(args)
        self.ind = 0

    def __iter__(self): #返回自身
        return self

    def next(self): # 返回数据
        if self.ind == len(self.data):
            raise StopIteration
        else:
            data = self.data[self.ind]
            self.ind += 1
            return data
## -- End pasted text --

In [9]: d  = DataIter(1,2)

In [10]: for x in d: # 开始迭代
   ....:     print x
   ....:
1
2

In [13]: d.next() # 只能迭代一次,再次使用则会抛异常
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
----> 1 d.next()
<ipython-input-1-c44abc1904d8> in next(self)
     10     def next(self):
     11         if self.ind == len(self.data):
---> 12             raise StopIteration
     13         else:
     14             data = self.data[self.ind]

next函数中只能向前取数据,一次取一个可以看出来,不过不能重复取数据


生成器(generator)

首先需要明确的就是生成器也是iterator迭代器,因为它遵循了迭代器协议.

两种创建方式

包含yield的函数

生成器函数跟普通函数只有一点不一样,就是把 return 换成yield,其中yield是一个语法糖,内部实现了迭代器协议,同时保持状态可以挂起。如下:
记住一点,yield是数据的生产者,而诸如for等是数据的消费者。

def gen():
    print 'begin: generator'
    i = 0
    while True:
        print 'before return ', i
        yield i
        i += 1
        print 'after return ', i

a  = gen()

In [10]: a #只是返回一个对象
Out[10]: <generator object gen at 0x7f40c33adfa0>

In [11]: a.next() #开始执行
begin: generator
before return  0
Out[11]: 0

In [12]: a.next()
after return  1
before return  1
Out[12]: 1

首先看到while True 不必惊慌,它只会一个一个的执行~
看结果可以看出一点东西:

  • 调用gen()并没有真实执行函数,而是只是返回了一个生成器对象

  • 执行第一次a.next()时,才真正执行函数,执行到yield一个返回值,然后就会挂起,保持当前的名字空间等状态。然后等待下一次的调用,从yield的下一行继续执行。

还有一种情况也会执行生成器函数,就是当检索生成器的元素时,如list(generator), 说白了就是当需要数据的时候,才会执行。

In [15]: def func():
   ....:     print 'begin'
   ....:     for i in range(4):
   ....:         yield i

In [16]: a = func()

In [17]: list(a) #检索数据,开始执行
begin
Out[17]: [0, 1, 2, 3]

yield还有其他高级应用,后面再慢慢学习。

生成器表达式

列表生成器十分方便:如下,求10以内的奇数:
[i for i in range(10) if i % 2]

同样在python 2.4也引入了生成器表达式,而且形式非常类似,就是把[]换成了().

In [18]: a = ( i for i in range(4))

In [19]: a
Out[19]: <generator object <genexpr> at 0x7f40c2cfe410>

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

可以看出生成器表达式创建了一个生成器,而且生有个特点就是惰性计算, 只有在被检索时候,才会被赋值。


小结

概括

主要介绍了大概这样几点:

  • 迭代器协议

    • 自定义可迭代对象与迭代器分离,保证数据复用

  • 生成器: 特殊的迭代器,内部实现了迭代器协议





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值