迭代器 Iterator与生成器Generator,从dict.keys()说起

21 篇文章 0 订阅
7 篇文章 0 订阅

在python2中,字典dict.keys()的内建方法会以列表list的形式返回字典的所有键。到了python3中,dict.keys()是以迭代器Iterator的形式生成的字典所有键。本文主要讲述迭代器Iterator,sorted方法,zip方法,生成器generator…以及Itertools库中常用的函数。

可迭代对象Iterable:
不管是列表list,数组array,字符串string,字典dict…我们都可以使用for循环来遍历traverse它们。这些数据结构被称为可迭代的Iterable的数据结构。
可迭代对象是实现了__iter__ ()方法的对象。
迭代器是实现了__iter__() 和 next()方法的对象。
所以一些可迭代对象比如列表list,字符串string,元组tuple,字典dict,并不是迭代器,但是我们可以通过iter()函数将它们转化为迭代器。下面是一张他们的关系图:
Itrable&Iterator

使用内建函数next(),iterator会每次给出下一个元素,当元素全部给出时,使用next()函数会报StopIteration异常(raise StopIteration exception)。

>>> a=[1,2,3]
>>> x=iter(a)
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

有一个需要提的细节是,当我们对字典进行iter()操作的时候,返回的是键keys的迭代器还是值values的迭代器呢?

>>> a={3:4,5:6}
>>> x=iter(a)
>>> next(x)
3
>>> next(x)
5
>>> 

很显然这里是返回了键的迭代器。

那么问题来了,已经有了数组等可迭代对象,我们用for循环结构就好了,为什么还需要迭代器呢?
这是因为我们需要迭代器的next()方法实现的延迟计算(lazy evaluation,也称为call-by-need, is an evaluation strategy which delays the evaluation of an expression until its value is needed ).
试想,在深度学习中,我们经常会读入很大的数据量, 然后将他们读入一个个batch。以读取RGB图片数据为例子,假设有5000张图片,一种比较笨拙的读取方法是,一次性将所有图片读入到一个数组中,这个数组大小可能是[5000, 128,128,3],将会耗费很大的内存,然而在取batch的时候,我们需要一个个batch从这个数组中把数据取出来。
如果使用迭代器呢?
我们使用next方法是不是直接从原始数据中一批批地读取就好,占用的内存会小很多。这就是call-by-need。
既然迭代器这么好用,那么我们在自定义的时候,每次都要事先__iter__()和__next__(),显得有点麻烦,所以我们使用了一种更为简洁的迭代器,它就是生成器generator。
生成器是为了让我们随心所欲定义迭代器而存在的,构建生成器的方式有两种:
1 使用生成器表达式
一般对于一些比较简单的生成器,我们可以直接用生成器表达式。
圆括号产生生成器,方括号产生列表。

>>> generator_express=(x*x for x in range(5))
>>> list=[x*x for x in range(5)]
>>> type(generator_express)
<class 'generator'>
>>> type(list)
<class 'list'>

2 使用yield关键字
在大部分函数中我们都用return关键字,一旦函数被调用,return将一次性返回相应的值。但是当一个生成器函数被调用时,生成器仅仅返回一个生成器对象,生成器函数并没有开始执行,只有当生成器函数调用next()方法时候,生成器函数才会开始执行,当函数将第一个yield关键字执行完,返回相应的yielded value就会停下,等待下一次next()函数,这也正是call-by-need。
以生成斐波那契数列为例子:

>>> def fib():
...     prev, curr = 0, 1
...     while True:
...         yield curr
...         prev, curr = curr, curr + prev
... 
>>> a=fib()
>>> next(a)
1
>>> next(a)
1
>>> next(a)
2
>>> next(a)
3
>>> next(a)
5
>>> next(a)
8

如果不加限制,这个fib()函数可以一直执行下去。

下面说说python的内建函数sorted()和zip()函数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值