Python中迭代对象、迭代器和生成器的比较

###本文从各路资料中摘取了一些进行整理,仅方便自己认识理解,不擅长文笔,见谅###

 

 

  首先简单看一下概念:

  • 迭代对象(iterable):可使用for.. in..进行循环的对象,比如list,tuble,dic,set,string以及迭代器、生成器等都是可迭代的对象。凡是可以返回有一个迭代器的对象都是可迭代的对象。可通过collections包中的isinstance来进行判断,例子如下:
    #判断是否为Iterable,可用isinstance
    >>> from collections import Iterable
    >>> isinstance({'dede':123},Iterable)
    True
    >>> isinstance('hello',Iterable)
    True
    >>> isinstance(123,Iterable)
    False
    >>> isinstance([1,3],Iterable)
    True
    #实现列表和元素的下表循环
    lanage=['python','php','java','c++']
    #第一种
    for x in range(len(lanage)):
    print(x,lanage[x])
    
    第二种
    for i ,value in enumerate(lanage):
    print(i,value)
    
    同一行输出
    for i ,value in enumerate(lanage):
    print(i,value ,end=','
     
  • 迭代器(Iterator):它是一个带状态的对象,他能在你调用next()方法的时候返回容器中的下一个值,任何实现了__iter____next__()(python2中实现next())方法的对象都是迭代器,__iter__返回迭代器自身__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常,至于它们到底是如何实现的这并不重要。迭代器就是实现了工厂模式的对象,它在你每次询问下一个值的时候给你返回。itertools函数返回的都是迭代器对象。
    #下面这段代码,通过迭代器的方式书写的一个斐波那契数列,来充分认识__next__和__iter__函数
    class
    Fib: def __init__(self): self.prev = 0 self.curr = 1 def __iter__(self): return self def __next__(self): value = self.curr self.curr += self.prev self.prev = value return value #islice可以使迭代器变为有限序列;cycle可使有限变为无限循环 from itertools import islice >>> f = Fib() >>> list(islice(f, 0, 10)) [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

    每次调用next()方法的时候做两件事:

    1. 为下一次调用next()方法修改状态
    2. 为当前这次调用生成返回结果

    迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。

      

我们看一张总概论图:

                 关系图

  可得出以下几点:

  • iterable>iterator>generator
  • 可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。
  • 迭代器持有一个内部状态的字段,用于记录下次迭代返回值,它实现了__next____iter__方法,迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。
  • 生成器是一种特殊的迭代器,它的返回值不是通过return而是用yield

  

最后我们看看生成器yield另一个应用例子

  另一个 yield 的例子来源于文件读取。如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取:

def read_file(fpath): 
   BLOCK_SIZE = 1024 
   with open(fpath, 'rb') as f: 
       while True: 
           block = f.read(BLOCK_SIZE) 
           if block: 
               yield block 
           else: 
               return

 

 

 

 

posted @ 2018-07-10 16:12  runningpp  阅读(87)  评论(0)    收藏  举报