python iterator(迭代器) and generator(生成器)

迭代:重复做一件事
iterable(可迭代)对象:支持“每次仅返回自身所包含的其中一个元素”的对象
iterable对象实现了__iter__方法
    序列类型,如:list、str、tuple
    非序列类型,如:dict、file
    用户自定义的一些包含了__iter__()或__getitem__方法的类       
    用dir(object)时,只要有__iter__()方法或__getitem__方法都是iterable对象。
    object.__iter__()   每运行一次,都返回一个迭代器对象的内存地址
    例:i1=list1.__iter__()       返回一个迭代器对象
           i1.next()
           i1.next()
           ....
           
迭代器(iterator)
    迭代器又称为游标(cursor),它是程序设计的软件设计模式,是一种可在容器物件(container)上实现元素遍历的接口。
    迭代器是一种特殊的数据结构,当然在python中,它也是以对象的形式存在的。简单理解方式:对于一个集体中的每一个元素,想要执行遍历,那么针对这个集体的迭代器就定义了遍历该集体中每一个元素的顺序或方法。 
    迭代器本身是不可逆的。
    可以使用一个“可迭代对象”的__iter__()方法生成一个“迭代器对象”
           In [31]: print list1
           [(1, 2), (3, 4), (5, 6)]
           In [32]: iterable1=list1.__iter__()
           In [33]: iterable1.next()
           Out[33]: (1, 2)
           In [34]: iterable1.next()
           Out[34]: (3, 4)
           In [35]: iterable1.next()
           Out[35]: (5, 6)
    也可以使用iter函数生成一个迭代器对象。用法: iter(container_object)
           In [37]: iterable1=iter(list1)
           In [38]: iterable1.next()
           Out[38]: (1, 2)
           In [39]: iterable1.next()
           Out[39]: (3, 4)
           In [40]: iterable1.next()
           Out[40]: (5, 6)

在python中,迭代器是遵循迭代协议的对象;使用iter()函数可以从任何序列对象中生成一个迭代器对象
若要使用迭代器,需要在类中定义next()方法(python3中是 __next__())
要使得迭代器指向下一个元素,则使用成员函数next() (在python3中,是函数next(),而非成员函数)
当没有元素时,则触发StopIteration异常
   
    for循环可用在任何可迭代对象:
    for循环开始时,会通过迭代协议传递给iter()内置函数,从而能够从可迭代对象中获得一个迭代器,返回的对象含有需要的next方法。
   
python的列表解析:
    根据一个已存在列表再生成另一个新列表时,可以使用列表解析功能。
    列表解析是python迭代机制的一种应用,它常用于实现创建新的列表,因此要放置于[]中。
    语法:[expression for iter_var in iterable_object]
               [expression for iter_var in iterable_object if condition_expression]

    例:
    list1=[1,2,3,4]
    list2=[ i**2 for i in list1]
    list3=[ i**2 for i in list1 if i%2==0 ]
    print list2,list3
       
    for i in [ x**2 for x in range(1,11)]: print i/2
       
    import os
    os.listdir("/path")     以指定目录中的所有文件为列表元素,返回一个新列表
    string.endswith(".suffix")  判断字符串对象是否以".suffix"为后缀,返回布尔值
   
    filelist2 = [ filename for filename in os.listdir("/var/log") if filename.endswith(".log") ]
    print filelist2
   
    list1=['x','y','z']
    list2=[1,2,3]
    list3=[ (i,j) for i in list1 for j in list2 ]       嵌套使用列表解析
    print list3
       
    list4=[ (i,j) for i in list1 for j in list2 if j%2!=0 ]
    print list4
       
    list5=range(10)
    list5=[str(i)  for i in list5] 将数字类型的列表转换成字符型的列表
       
    list6=range(10)
    list6=[str(i)+'\n'  for i in list6] 将数字类型的列表转换成字符型的列表,并在每个元素后面加上一个"\n"的字符串
    f=file('/tmp/newfile','w+')
    f.writelines(list6)
    f.close()
    ipython需要使用SQLite才支持命令历史,否则不支持

Python生成器 
    如果元素过多,列表解析就特别占用资源。使用生成器,一次只生成一个元素,节省资源。   
    生成器表达式并不真正创建数字列表,而是返回一个生成器对象,此对象在每次计算出一个条目后,把这个条目"产生"(yield)出来。
    生成器表达式使用了"惰性计算"或称为"延迟求值"的机制。
    序列过长,并且每次只需要猎取一个元素时,就应当考虑使用生成器表达式而不是列表解析。生成器表达式用于python2.4以后的版本
    语法: (expression for iter_var in iterable)
        (expression for iter_var in interable if condition_expression)
        例:
        generator1=( i**2 for i in range(1,11))
        generator1.next()
    当然可以使用for遍历生成器,在遍历生成器时才生成值、每次只创建一个值,生成器尽量延迟生成值。
    每次仅从函数中取yield值一次,然后记录位置,下次从本次的位置继续取值。
       
    for x in ( i**2 for i in range(1,11)): print x/2
       
    例:剖析yield运行过程
       def func1():
           yield 1
           yield 2
           yield 3
       g1=func1()
       '''print g1.next()
       print g1.next()
       print g1.next()
       '''
       for item in g1:
           print item

       例:自定义一个xxreadlines()函数,逐行读取文件的内容
       def xxreadlines(filename):
           seek=0
           while True:
               with open(filename,"r") as f:
                   f.seek(seek)
                   data=f.readline()
                   if data:
                       seek=f.tell()
                       yield data
                   else:
                       return
       g1=xxreadlines("/tmp/test1")
       print g1.next()
       print g1.next()
       说明:with在打开文件后自动close;yield可以保留函数运行过程中的状态。
       
产生偏移和元素enumerate
    range 可在非完备遍历中用于生成索引偏移,而非偏移元素。
    如果同时需要偏移索引和偏移元素,则可以使用enumerate()函数
    此内置函数返回一个生成器对象 
    例:
        In [67]: str1="www.example.com"
        In [68]: e1=enumerate(str1)
        In [69]: e1.next()      返回值既有索引,又有元素
        Out[69]: (0, 'w')
        In [70]: e1.next()
        Out[70]: (1, 'w')
        In [71]: e1.next()
        Out[71]: (2, 'w')
        In [72]: e1.next()
        Out[72]: (3, '.')
        In [73]: e1.next()
        Out[73]: (4, 'e')










本文转自 meteor_hy 51CTO博客,原文链接:http://blog.51cto.com/caiyuanji/1833959,如需转载请自行联系原作者
上一篇:spring使用中报Cannot proxy target class because CGLIB2 is not available错


下一篇:小程序:在{{}}中使用函数