资讯专栏INFORMATION COLUMN

python迭代器资料整理

Muninn / 3448人阅读

摘要:满足以上要求的对象,就是迭代器。其中,必需返回一个迭代器对象,则负责迭代逻辑并在迭代完毕时触发异常。可以在遍历迭代器的时候,加入一个判断语句,避免无法多次迭代的情况发生参考资料官网迭代器文档

什么是迭代器 相关概念定义 迭代器(Iterator):

满足迭代协议的对象就是迭代器
iterator就是实现了Iteration Protocol的对象,这类对象都支持循环遍历的操作(for/while/支持迭代的函数list() sum()...)。

迭代协议(Iteration Protocol):

内建函数iter()接收一个可迭代对象,并返回一个可迭代对象.
每次将这个可迭代对象传递给next()函数,都会返回它所包含的下一个元素,当迭代完最后一个元素时,就会触发StopIteration异常。

>>> x = iter([1, 2, 3])
>>> x

>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
Traceback (most recent call last):
  File "", line 1, in 
StopIteration

满足以上要求的对象,就是迭代器。

迭代隐含的操作

在每次的迭代语句中,python都会按照迭代协议去对迭代器进行迭代。其实,在实际执行中,python会进行一些其他的操作:

将需要迭代的对象作为参数传递给iter函数

iter返回一个迭代器对象

每次循环则将返回的迭代器对象传递给next函数

循环至最后一个元素,触发StopIteration

for语句为例
当我们在Python中执行循环语句for i in foo的时候,其背后的操作是:

foo = iter(foo)

next(foo)

next(foo)在python3中执行的是:foo.__next__(),在python2中则是:foo.next()

迭代器的实现

迭代器是用class来实现的。其中必需实现的有两个方法:__iter__next(python2)/__next__(python3)。其中,__iter__必需返回一个迭代器对象,next则负责迭代逻辑并在迭代完毕时触发异常。

如下:

def Iter(object)
    def __init__(self):
        pass
    def __iter__(self):
        pass
    def __next__(self):    # python3
        pass
    def next(self):        # python2
        pass

迭代器的特殊情况 迭代器的__iter__返回self

迭代器的__iter__方法需要返回的是一个具有next方法的可迭代对象。如果当__iter__返回的是self的话,就会产生其他意想不到的效果。

class yrange:
    def __init__(self, n):
        self.i = 0
        self.n = n

    def __iter__(self):
        return self

    def next(self):
        if self.i < self.n:
            i = self.i
            self.i += 1
            return i
        else:
            raise StopIteration()
            
class zrange:
    def __init__(self, n):
        self.i = 0
        self.n = n

    def __iter__(self):
        return zrange(self.n)
        
    def next(self):
        if self.i < self.n:
            i = self.i
            self.i += 1
            return i
        else:
            raise StopIteration()

执行结果:

>>> y = yrange(5)
>>> list(y)
[0, 1, 2, 3, 4]
>>> list(y)
[]
>>> z = zrange(5)
>>> list(z)
[0, 1, 2, 3, 4]
>>> list(z)
[0, 1, 2, 3, 4]

yrange中,iter返回的是self,在执行list(y)iter返回的都是同一个self,所以再次调用list(y)时只会触发结束迭代异常,列表中并无内容。
而在zrange中,每次执行list(z)时,iter都是返回一个新的迭代器zrange(self.n),所以每次执行list(z)都得到完整的元素。

生成器的迭代

通常,对于数据量特别大的序列,我们会用生成器generator来代替容器对象container,这样可以利用lazy evaluable来节省内存开销。值得注意的是,生成器也是一个只能迭代一次的迭代器。

def grange(n):
    i = 0
    while i < n:
        yield i
        i += 1

执行结果:

>>> glist = grange(10)
>>> list(glist)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(glist)
[]

如果是利用便捷的生成器表达式也是一样:

>>> alist = (i for i in range(10))
>>> list(alist)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(alist)
[]

要解决这个问题,可以将迭代器和生成器组合使用:

class Grange(object):
    def __init__(self, n):
        self.n = n
    
    def __iter__(self):
        for i in range(self.n):
            yield i

结果:

>>> glist = Grange(10)
>>> list(glist)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(glist)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

值得注意的是,平常我们利用到生成器的地方都是数据量特别大的情况,这个时候,其实应该尽量避免多次迭代生成器。我想这应该也是python没有支持对生成器多次迭代的特性的原因。

编程建议

在实际的编程中,往往需要在函数中多次迭代一个序列,如果这个序列是调用API得到的,而你又不能保证它是没有陷阱的迭代器时。可以在遍历迭代器的时候,加入一个判断语句,避免无法多次迭代的情况发生:

def iterator_checker(iterator):
    assert iter(iterator) is not iter(iterator), "iter() return self"
参考资料

python官网迭代器文档

python practice book

<>

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38062.html

相关文章

  • Python学习--最完整的基础知识大全

    摘要:迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器有两个基本的方法和。调用一个生成器函数,返回的是一个迭代器对象。生成器函数生成器函数返回一个迭代器函数函数传入不定长参数加了星号的变量名会存放所有未命名的变量参数。 Python学习--最完整的基础知识大全 关于python的基础知识学习,网上有很多资料,今天我就把我收藏的整理一下分享给大家! 菜鸟教程pytho...

    王笑朝 评论0 收藏0
  • 每天一个设计模式·迭代模式

    摘要:迭代器模式原文地址更多设计模式系列教程更多免费教程博主按每天一个设计模式旨在初步领会设计模式的精髓,目前采用靠这吃饭和纯粹喜欢两种语言实现。迭代器模式常见和常用的有内部迭代器外部迭代器倒序迭代器等等。 迭代器模式·原文地址 更多《设计模式系列教程》 更多免费教程 博主按:《每天一个设计模式》旨在初步领会设计模式的精髓,目前采用javascript(靠这吃饭)和python(纯粹喜欢...

    沈俭 评论0 收藏0
  • 每天一个设计模式·迭代模式

    摘要:迭代器模式原文地址更多设计模式系列教程更多免费教程博主按每天一个设计模式旨在初步领会设计模式的精髓,目前采用靠这吃饭和纯粹喜欢两种语言实现。迭代器模式常见和常用的有内部迭代器外部迭代器倒序迭代器等等。 迭代器模式·原文地址 更多《设计模式系列教程》 更多免费教程 博主按:《每天一个设计模式》旨在初步领会设计模式的精髓,目前采用javascript(靠这吃饭)和python(纯粹喜欢...

    newsning 评论0 收藏0
  • 首次公开,整理12年积累的博客收藏夹,零距离展示《收藏夹吃灰》系列博客

    摘要:时间永远都过得那么快,一晃从年注册,到现在已经过去了年那些被我藏在收藏夹吃灰的文章,已经太多了,是时候把他们整理一下了。那是因为收藏夹太乱,橡皮擦给设置私密了,不收拾不好看呀。 ...

    Harriet666 评论0 收藏0
  • 干货 | 学习Python的正确姿势

    摘要:勤学学习效率与效果取决于执行力。这一步学习的正确姿势是在实践操作中发掘问题,然后带着问题找答案。拆分任务将目标分解成具体可执行的学习任务。勤学强大的执行力是学习的根本保障。分享复述检验学习成果,提高学习效果的最好方法。 showImg(https://segmentfault.com/img/bVbcPGZ?w=256&h=256); 前段时间和大家一起分享了一篇关于学习方法内容《大牛...

    Thanatos 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<