Python-迭代器VS生成器

1.定义

可迭代对象(Iterable类型):可迭代对象是指任何定义了__iter__方法的对象。可迭代对象的__iter__方法负责返回一个迭代器。

迭代器(Iterator类型):Python中的迭代器是包含__next__方法(即,能够响应next函数)的任何对象。Iterator对象表示一个惰性计算序列。只能不断通过next()函数实现按需计算下一个数据,直到遇到StopIteration错误。

生成器(Geneator类型):生成器是一种迭代器。与普通函数不同,生成器只会在响应迭代操作时才会运行。

生成器可以是迭代器,但不一定是迭代对象;并非所有的迭代器都是迭代对象。

Python中for循环用于对序列(例如字符串、元组或列表)或其他可迭代对象中的元素进行迭代。所有能用于for循环的对象都是Iterable类型。for循环的本质就是不断调用next()函数。Python中for循环的用法类似于Java中的foreach。

for i in [1,2,3,4]:
    pass
print(i)

在Python语言中,for循环中定义的变量i在退出for循环时的值等于可迭代对象的最后一个值。for循环的具体执行过程如下:

  • [1,2,3,4]通过iter()转化成迭代器。
  • 然后对该迭代器调用next()函数,不断输出迭代器中的内容,并复制给i
  • 连续执行4次next()之后,i等于4,继续执行next()函数,抛出StopIteration异常。for循环结束。

2.双层for循环中使用迭代器和生成器

从上面的代码中可以看出enumerate()产生的生成器在双层for循环中并没有达到我们要的效果。

3.自定义可迭代对象及迭代器

3.1 自定义可迭代对象(在类定义中实现__iter__函数)

这种写法实际上是一种委托迭代的写法,这里的迭代方式借助了其他迭代对象。

class Node(object):
    def __init__(self):
        self._children=[]
    def add_child(self,value):
        self._children.append(value)
    def __iter__(self):
        return iter(self._children)
if __name__=="__main__":
    node_1=Node()
    node_1.add_child(5)
    node_1.add_child(4)
    for node in node_1:
        print(node)

3.2 用生成器创建新的迭代方式

python中的range()只能接受整数,如果想要一个能够接受浮点型的类range()的话,可以使用yield构造一个生成器。

def frange(start,stop,increment):
    x=start
    while x<stop:
        yield x
        x+=increment
a=frange(1,5,0.5)
for i in a:
    print(i,end=' ')

4.其他

4.1 反向迭代

反向迭代的实现主要内建函数reversed()和__reversed__()函数。以实现倒计时类为例:

class CountDown(object):
    def __init__(self,start):
        self.start=start
    def __reversed__(self):
        n=self.start
        while n>0:
            yield n
            n-=1
countDown=CountDown(10)
for item in reversed(countDown):
    print(item)
  • 如果在CountDown类中只实现了__reversed__()方法,而没有实现__iter__()方法的话,countDown(CountDown的实例)不能使用for in中。因为countDown不是可迭代对象,不是迭代器,更不是生成器。
  • 由于在CountDown类中实现了__reversed__()方法,所以countDown可以响应reversed()函数。并且reversed(countDown) 可以使用for  in  语法。

4.2 对迭代器做切片操作

list对象可以在中括号[]执行普通的切片操作,但是对其他迭代器则是无法直接使用切片操作。主要有以下两个方面的原因:

  • 首先,通常我们无法准确地知道迭代器和生成器的准确长度
  • 其次,一般迭代器和生成器都没有实现索引。

如果想对迭代器和生成器使用类似切片操作,可以使用itertools.islice()函数。islice()函数可以产生一个迭代器,并产生所需要的切片元素。

import itertools
def count(n):
    while True:
        yield n
        n+=1
c=count(10)
for i in itertools.islice(c,1,5):
    print(i)
print("==========")
for i in itertools.islice(c,2,5):
    print(i)
b=list(range(50))
print("===========")
for i in itertools.islice(b,1,5):
    print(i)
print("============")
for i in itertools.islice(b,2,5):
    print(i)

代码运行结果如下:

从以下代码运行结果可以看出,islice()会消耗掉所提供的迭代器中的数据。但是对于list列表中的数据,并没有被消耗。

11

12

13

14

==========

17

18

19

==========

1

2

3

4

==========

2

3

4

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值