首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python自学成才之路 迭代器的使用

Python自学成才之路 迭代器的使用

作者头像
我是李超人
修改2020-08-30 20:28:47
3540
修改2020-08-30 20:28:47
举报

可迭代对象 实现了__iter__魔术方法的对象是可迭代对象(Iterable)

迭代器 实现了__iter__和__next__魔术方法的对象是迭代器(Iterator)

迭代器和可迭代对象的区别在于迭代器是可以通过for循环来遍历的,而可迭代对象如果没有实现__next__魔术方法是不能用for来遍历的。

判断一个对象是否是可迭代对象 使用isinstance()判断一个对象是否是Iterable

from collections import Iterable, Iterator
ret = isinstance([1, 2, 3], Iterable)
print(ret)

ret = isinstance((1, 2, 3), Iterable)
print(ret)

ret = isinstance("abc", Iterable)
print(ret)

ret = isinstance(123, Iterable)
print(ret)

输出:
True
True
True
False

创建一个迭代器 要求:实现__iter__()魔术方法并返回一个特殊的可迭代对象,这个可迭代对象需要实现 next() 方法并通过 StopIteration 异常标识迭代的完成。 咋一看可能不太懂什么意思,下面通过几个案例讲解下。

实现了__iter__()魔术方法的对象是一个可迭代对象,但是没法通过for循环进行遍历。

from collections import Iterable, Iterator

class MyRangeIterator(object):
    def __init__(self, start, end):
        self.index = start
        self.end = end

    def __iter__(self):
        return self


myrange = MyRangeIterator(1, 2)
print(isinstance(myrange, Iterable))

for x in myrange:
    print(x)
    
输出:
True
Traceback (most recent call last):
  File "D:/pycharm workspace/oopdemo/iterator_generator/IteratorDemo03.py", line 22, in <module>
    for x in myrange:
TypeError: iter() returned non-iterator of type 'MyRangeIterator'

这个MyRangeIterator对象实现了__iter__魔术方法,返回的是它自身实例,但是MyRangeIterator并没有实现__next__()魔术方法,所以没法使用for遍历,下面实现__next__魔术方法后就可以使用for遍历了。

class MyRangeIterator(object):
    def __init__(self, start, end):
        self.index = start
        self.end = end

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < self.end:
            temp = self.index
            self.index += 1
            return temp
        else:
            raise StopIteration()

myrange = MyRangeIterator(1, 3)
print(isinstance(myrange, Iterable))

for x in myrange:
    print(x)
    
输出:
True
1
2

注意:在实现__next__魔术方法的时候,当遍历完成后需要抛出StopIteration异常,否则迭代过程不会停下来。 __next__魔术方法对应的是next()函数,所以上面的迭代器对象还可以这样使用。

print(next(myrange))

在使用for循环遍历的时候,内部其实是自动通过next函数来取值。

上面那种__iter__方法直接返回自身实例来实现迭代器的方式实际上有个坑,还是上面那个案例,如果使用两个for循环来遍历,第二个for循环遍历不到值。

myrange = MyRangeIterator(1, 3)
print(isinstance(myrange, Iterable))

for x in myrange:
    print(x)

for y in myrange:
    print(y)
输出:
True
1
2

第二个for循环没有值输出,原因是myrange这个实例的index值发生了变化,所以再使用for遍历的时候,index已经达到最大值了,不会再取到值。所以实现迭代器最好的方法是每次都返回一个迭代器实例,像下面这样。

class MyRangeIterator(object):
    def __init__(self, start, end):
        self.index = start
        self.end = end

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < self.end:
            temp = self.index
            self.index += 1
            return temp
        else:
            raise StopIteration()


class MyRange(object):

    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __iter__(self):
        return MyRangeIterator(self.start, self.end)


ret = MyRange(1, 3)
for x in ret:
    print(x)
print("="*10)
for y in ret:
    print(y)
输出:
1
2
==========
1
2

这个例子中MyRange没有实现__next__方法,而是在__iter__魔术方法中返回了一个实现了__next__的可迭代对象。所以它也是一个迭代器对象,而且每次使用for遍历的时候都会通过__iter__返回一个新的MyRangeIterator实例。

其实文章开头对迭代器的定义有点不准确,实际还可以通过生成器的方式来得到迭代器,下一节会介绍生成器!

本人是做大数据开发的,在微信上开了个个人号,会经常在上面分享一些学习心得,原创文章都会首发到公众号上,感兴趣的盆友可以关注下哦!

大数据入坑指南
大数据入坑指南
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-08-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档