python迭代器与生成器详解

__iter____next__

先看一个开发中常见的for循环的应用:

a=[1,2,3]for i in a:    print(i)123

a是一个列表,自身也是一个迭代器(iterator);for循环可能遍历的肯定是iterator,在遍历时会默认调用迭代器的iter()办法,将其显示进去,即等价于:

for i in iter(a):    print(i)123

在了解迭代器之前,必须要了解魔法办法__iter____next__的调用。下面例子iter(a)的背地就是调用对象a的__iter__办法,即a.__iter__();

iter(a)返回的是什么?返回的是一个外部实现了__next__()办法的对象,每次调用__next__()来弹出下一个值,以此来实现遍历。

举例:

class A(object):    def __init__(self,a):        self.a=a    def __next__(self):           print('this is next')        if self.a<6:            self.a+=1            return self.a        else:            raise StopIteration            class B(object):    def __init__(self):        pass    def __iter__(self):        print('this is iter')        return A(a=0)    >>>b=B()>>>for i in b:#实质上是调用iter(b),或者b.__iter__();返回了一个实现了__next__办法的实例对象。>>>    print(i) this is iter#首先调用iter(b)this is next#调用A的next,返回值为以后的i。1this is next2this is next3this is next4this is next5this is next6this is next#for 循环会主动捕捉StopIteration异样。

值得注意的是两个概念:

  • 可迭代对象(Iterable):类中实现了__iter__的就能够叫iterable了,个别__iter__返回的是一个实现了__next__办法的对象实例。这一点不强制。如果本人自身就实现了__next__办法,天然就能够返回self。
  • 迭代器(Iterator):类中实现了__iter____next__办法的对象。短少任何一个都不能叫iterator;迭代器天然也是一个iterable。

如下面A,B两个类的实例对象,A(0)既不是Iterable也不是Iterator;B()是Iterable但不是Iterator

from collections.abc import Iterable,Iterator>>>isinstance(a, Iterable)False>>>isinstance(a, Iterator)False>>>isinstance(b, Iterable)True>>>isinstance(b, Iterator)False

python中内置的可迭代对象:列表、元组、字典、汇合字符串和open()关上的文件等都是;留神这些都不是迭代器Iterator;因为对于迭代器,咱们不能提前晓得序列的长度,只能一直通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在须要返回下一个数据时它才会计算。而显著列表、元组、字典等咱们是能够把握全局信息的。

迭代器Iterator

依据__iter____next__来定义本人的迭代器:

class Myrange(object):    def __init__(self,stop,start=0):        self.start=start        self.stop=stop    def __iter__(self):        return self    def __next__(self):        if self.start<self.stop:            res=self.start            self.start+=1        else:            raise StopIteration        return res    for i in Myrange(3):    print(i)   012>>>isinstance(Myrange(3),Iterable)True>>>isinstance(Myrange(3),Iterator)True>>>type(Myrange(3))<class '__main__.Myrange'>

生成器

python提供了一种非凡的yield办法,来使函数对象间接转换为一个迭代器。生成器就是一类非凡的迭代器。每当程序执行到yield的时候,程序就暂停在这里,处于挂起状态,而后把返回的货色返回当前,再继续执行原来的程序。

def func(end):    start=0    while start<end:        yield start        start+=1from collections.abc import Iterable,Iterator>>>print(isinstance(func(3),Iterator))>>>print(isinstance(func(3),Iterable))>>>for i in func(3):>>>    print(i)    True#是一个可迭代对象True#是一个迭代器012>>>a=func(4)>>>print(next(a))>>>print(a.__next__())01>>>print(type(a))<class 'generator'>>>>print(isinstance(a,Generator))#也是一个生成器类型。<class 'generator'>

从迭代器或者生成器的原理能够看到,其最大的特点就是能够节俭内存。同样遍历一个有100000万条整数的列表和生成器,耗费的内存是齐全不一样的。列表须要全副把物理空间开辟出来来先保留这些数据,而生成器以此只须要保留一个数据即可。

import sys>>>a=range(1000000)>>>sys.getsizeof(a)48>>>b=list(range(1000000))>>>sys.getsizeof(b)8000056

而生成器应用的场景有节俭内存的益处,有个前提就是咱们可能依照某种算法推算出来,在循环的过程中一直推算出后续想要的元素。

总结

  • 实现了__iter__办法的对象为可迭代对象(Iterable),常见的Iterable有list,dict,tuple,range等;同时实现了__iter____next__办法的为迭代器(Iterator);函数中利用yield关键字的对象为生成器(Generator),生成器也是一种迭代器和可迭代对象。
  • 迭代器Iterator、生成器Generator都须要通过for循环,或者手动调用next()来一一获取其外部值
  • 迭代器、生成器的应用能够节俭内存,但前提是咱们可能依照某种算法推算出来,在循环的过程中一直推算出后续想要的元素。
  • 生成器的其它应用场景能够参考https://www.zhihu.com/questio...
  • 最初,容器、迭代器、生成器、可迭代对象的关系能够用下图总结: