当前位置: 首页 > 后端技术 > Python

python迭代器和生成器详解

时间:2023-03-26 00:03:57 Python

python迭代器和生成器详解__iter__和__next__先看开发中常用的一个for循环的使用:a=[1,2,3]foriina:print(i)123a是一个列表,也是一个迭代器;迭代器必须通过for循环遍历,遍历时默认会调用迭代器的iter()方法,并显示出来,相当于:foriiniter(a):print(i)123在理解迭代器之前,你必须理解魔法方法__iter__和__next__的调用。上面例子iter(a)背后就是调用对象a的__iter__方法,即a.__iter__();iter(a)返回什么?返回的是一个对象,内部实现了__next__()方法,每次调用__next__()弹出下一个值,完成遍历。示例:classA(object):def__init__(self,a):self.a=adef__next__(self):print('thisisnext')ifself.a<6:self.a+=1returnself.一个else:raiseStopIterationclassB(object):def__init__(self):passdef__iter__(self):print('thisisiter')returnA(a=0)>>>b=B()>>>foriinb:#Essentiallycalliter(b),orb.__iter__();返回一个实现了__next__方法的实例对象。>>>print(i)thisisiter#Firstcalliter(b)thisisnext#调用A的next,返回值为当前i。1thisisnext2thisisnext3thisisnext4thisisnext5thisisnext6thisisnext#for循环会自动捕获StopIteration异常。值得注意的两个概念:可迭代对象(Iterable):实现了__iter__的类可以称为可迭代的,一般__iter__返回一个实现了__next__方法的对象实例。这不是强制性的。如果自己实现__next__方法,自然可以返回self。迭代器(Iterator):类中实现了__iter__和__next__方法的对象。没有它们中的任何一个都不能调用迭代器;迭代器自然是可迭代的。对于上面两个类A和B的实例对象,A(0)既不是Iterable也不是Iterator;B()是Iterable但不是Iteratorfromcollections.abcimportIterable,Iterator>>>isinstance(a,Iterable)False>>>isinstance(a,Iterator)False>>>isinstance(b,Iterable)True>>>isinstance(b,Iterator)FalsePython的内置迭代器:列表、元组、字典、字符串集合和open()请注意,这些不是迭代器Iterator;因为对于迭代器来说,我们无法预先知道序列的长度,只能通过next()函数来按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要下一个数据的时候才会计算被退回。而显然列表、元组、字典等我们可以掌握全局的信息。IteratorIterator根据__iter__和__next__定义自己的迭代器:classMyrange(object):def__init__(self,stop,start=0):self.start=startself.stop=stopdef__iter__(self):returnselfdef__next__(self):如果self.start>>isinstance(Myrange(3),Iterable)True>>>isinstance(Myrange(3),Iterator)True>>>type(Myrange(3))generatorpython提供了一个特殊的yield方法可以直接将函数对象转换为一个迭代器。生成器是一种特殊的迭代器。每当程序执行到yield时,程序就被挂到这里,处于挂起状态,然后把返回的东西返回,然后继续执行原来的程序。deffunc(end):start=0whilestart>>print(isinstance(func(3),Iterator))>>>print(isinstance(func(3),Iterable))>>>foriinfunc(3):>>>print(i)True#isaniterableobjectTrue#isaniterator012>>>a=func(4)>>>print(next(a))>>>print(a.__next__())01>>>print(type(a))>>>print(isinstance(a,Generator))#也是一个生成器类型。从迭代器或生成器的原理可以看出,它最大的特点就是可以节省内存。类似地,遍历具有100,000个整数的列表和生成器消耗的内存完全不同。列表需要先开辟所有的物理空间来保存这些数据,生成器只需要保存一个数据即可。importsys>>>a=range(1000000)>>>sys.getsizeof(a)48>>>b=list(range(1000000))>>>sys.getsizeof(b)8000056以及生成器使用的场景节省内存的好处有一个前提,就是我们可以按照一定的算法进行计算,在循环的过程中不断的计算出后面想要的元素。总结实现了__iter__方法的对象是可迭代对象(Iterable)。常见的Iterables包括list、dict、tuple、range等;实现了__iter__和__next__方法的是迭代器(Iterator);function应用yield关键字的对象是生成器,生成器也是迭代器和可迭代对象。Iterators和Generators需要经过for循环,或者手动调用next()来逐个获取它们的内部值。使用迭代器和生成器可以节省内存,但是前提是我们可以按照一定的算法进行计算。在不断推演后续所需元素的过程中。生成器的其他使用场景可以参考https://www.zhihu.com/questio...最后,容器、迭代器、生成器、可迭代对象的关系可以总结为下图: