可迭代、迭代器、生成器解析

概括

  • 容器是一系列元素的集合,str、tuple、list、set、dict、file、sockets类型的对象都可以看作是容器。
  • 一个对象实现了__iter__()方法,就是可迭代对象。容器都都是可迭代对象,他们可以在for…in…,while…语句中被迭代。
  • 一个对象同时实现了__iter__()方法与__next__()方法,或者说一个可迭代对象实现了__next__()方法,就是迭代器。迭代器持有一个内部状态的字段,用于记录下次迭代返回值,迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。
  • 生成器是一种特殊的迭代器,它的返回值不是通过return而是用yield。

可迭代对象

一个对象实现了__iter__()方法,就是可迭代对象。我们通过两种方法判断str、tuple、range、list、set、dict类型的容器是否为可迭代对象。一种方法是通过dir()函数查看目标对象是否具有__iter__()方法;另一种方法是从collections模块中导入Iterable属性,利用isinstance()函数判断目标对象是否为Iterable类型,如果是的话,该目标对象即为可迭代对象。

s = 'my name is david'              #str类型
t = (1,2,3,'a','5')                 #tuple类型
r = range(10)                       #range类型
l = [1,2,3,4,5]                     #list类型
st = {'a','b','c',4,5}               #set类型
d = {'a':1,'b':2,'c':3,'d':4}       #dict类型

from collections import Iterable      #使用Iterable属性判断目标对象是否为可迭代对象
print(isinstance(s,Iterable))
print(isinstance(t,Iterable))
print(isinstance(r,Iterable))
print(isinstance(l,Iterable))
print(isinstance(st,Iterable))
print(isinstance(d,Iterable))

迭代器

一个对象同时实现了__iter__()方法与__next__()方法,就是迭代器。为了更直观地感受迭代器,我们自定义一个斐波那契数列类Fib,将该类实例化之后可以生成迭代器。

class Fib:
    def __init__(self):
        self.prev = 0
        self.curr = 1
    def __iter__(self):   #一个对象实现__iter__()方法,就是可迭代对象。
        return self 
    def __next__(self):    #一个可迭代对象实现__next__()方法,就是迭代器。
        value = self.curr
        self.curr += self.prev
        self.prev = value
        return value

f = Fib()
from collections import Iterable, Iterator
print(isinstance(f,Iterable))    #f既是可迭代对象
print(isinstance(f,Iterator))    #f也是迭代器

在这里,我们通过建立一个Fib类,然后实例化为一个f对象的形式自定义一个迭代器。可以说自定义迭代器的方式是比较笨拙的,后面我们会介绍生成器,与迭代器相比,自定义生成器是比较简洁、优雅的。

迭代器不会一次性将所有的元素都加载到内存,等到使用next()调用的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。itertools模块中的函数返回的都是迭代器对象。

from collections import Iterator

from itertools import count
counter = count(start=13)
print(isinstance(counter,Iterator))

from itertools import cycle
colors = cycle(['red','yellow','blue'])
print(isinstance(colors,Iterator))

from itertools import islice
iterslice = islice(counter,2,12)
print(isinstance(iterslice,Iterator))

使用python内置函数iter()可以将可迭代对象变成迭代器。

from collections import Iterator
s = 'my name is david'              #str类型
t = (1,2,3,'a','5')                 #tuple类型
r = range(10)                       #range类型
l = [1,2,3,4,5]                     #list类型
st = {'a','b','c',4,5}               #set类型
d = {'a':1,'b':2,'c':3,'d':4}       #dict类型
si = iter(s)
print(isinstance(si,Iterator))
ti = iter(t)
print(isinstance(ti,Iterator))
ri = iter(r)
print(isinstance(ri,Iterator))
li = iter(l)
print(isinstance(li,Iterator))
sti = iter(st)
print(isinstance(sti,Iterator))
di = iter(d)
print(isinstance(di,Iterator))

Python 3中关于iter(object[, sentinel])方法有两个参数。 使用iter(object)这种形式比较常见。 iter(object, sentinel)这种形式一般较少使用,Python的文档说明貌似也不容易理解。

生成器

生成器(generator)是一种特殊的迭代器,与迭代器相比,生成器更为优雅。它不需要再像上面的类一样写__iter__()和__next__()方法,只需要一个yiled关键字,像定义函数一样自定义生成器。我们创建了一个生成器后,基本上永远不会调用next()方法,而是通过for循环来迭代它。 与自定义迭代器相比,下面这种使用生成器来创建斐波那契数列的方式是不是更优雅?

def fib():
    prev, curr = 0, 1
    while True:
        yield curr
        prev, curr = curr, curr + prev
f = fib()           #创建迭代器
from itertools import islice   #导入迭代器切片工具
list(islice(f,0,10))

此外,我们还可以使用生成器表达式来构造生成器。与列表生成式类似,只需要把一个列表生成式的[]改成(),就可以创建一个生成器。

>>> l = [x*x for x in range(10)]
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000026428DEC308>

转载于:https://my.oschina.net/u/3861934/blog/1864001

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值