• python迭代器和生成器


    什么是迭代器?

    首先我们得明白迭代是什么,迭代是一个重复的过程,下一次结果的产生是基于上一次的结果。

    python中为什么会有迭代器,我们知道python中一些有索引的序列类型,如list,tuple,str,我们可以使用索引的方式迭代取出其包含的元素。

    但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,也就是它应该具有遍历复杂数据结构的能力,这就是迭代器。

    什么是可迭代对象?

    在python中可迭代对象指的是内置有__iter__方法的对象。

    #可迭代对象
    l=[0,8]
    dic={'das':88}
    l.__iter__()
    dic.__iter__()

    什么是迭代器对象?

    在python中迭代器对象指的是即内置有__iter__又内置有__next__方法的对象

    #迭代器对象
    with open('ad.txt','r') as f:
        f.__iter__()
        f.__next__()
    可迭代对象和迭代器对象都有__iter__方法,那么有什么区别呢?
    可迭代对象.__iter__()得到的是一个迭代器对象
    迭代器对象.__iter__()得到的仍然是迭代器对象本身
    也就是说迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
    l=[0,8]
    dic={'das':88}
    obj=l.__iter__()
    obj1=dic.__iter__()
    obj.__next__()
    obj.__iter__()
    obj1.__next__()
    obj1.__iter__()
    #迭代器对象
    with open('ad.txt','r') as f:
        f1=f.__iter__()
        print(f1==f,f1 is f)#这里是true
        f.__next__()
    迭代器对象.__next__()方法是做什么的呢
    这里的__next__()方法就是用来取值的
    l=[0,8]#l是可迭代对象
    obj_l=l.__iter__()#obj_l是迭代器对象
    print(obj_l.__next__())#输出0
    print(obj_l.__next__())#输出8
    print(obj_l.__next__())#报错StopIteration

    这里我们没有按索引取值,但是去拿到了列表l里的值。那我们再来看看其他没有索引的

    dic={'x':221,'y':3213,'z':132}
    iter_dic=dic.__iter__() #先得到迭代器对象,不管是迭代器对象还是可迭代对象
    print(iter_dic.__next__()) 
    print(next(iter_dic)) #等同于iter_dic.__next__()
    print(iter_dic.__next__()) #当然这里3个输出会是无序的 ---->x y z
    print(iter_dic.__next__()) #再继续就,抛出异常StopIteration,或者说结束了

    当然也可以用循环的方式取值

    dic={'x':221,'y':3213,'z':132}
    iter_dic=dic.__iter__()#先得到迭代器对象,不管是迭代器对象还是可迭代对象
    while True:
        try:
            print(next(iter_dic))  # 等同于iter_dic.__next__() 取出来是dic的键
        except StopIteration:
            break

    上面的循环取值就跟python中的for循环一样的

    这里我们可以了解一下for循环的机制:

    dic={'x':221,'y':3213,'z':132}
    for i in dic:
        print(i)
    1:先执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
    2: 执行iter_dic.__next__()或是next(iter_dic),将得到的值赋值给i,然后执行循环体代码(类似上面的while循环)
    3: 重复过程2,直到捕捉到异常StopIteration,结束循环

    重要的是for循环in后面的对象一定得是可迭代对象!!!
    迭代器的优缺点:
    优点: 提供不依赖于索引的取值方式 惰性计算,节省内存,这里可以去打印迭代器看看, 只有next的时候才计算值  
    缺点: 无法获取长度(只有在next完毕才知道到底有几个值),打印迭代器看到的是一个地址 一次性的,只能往后走,不能往前退(只能一条道走到黑,回不到从前了


    生成器是什么呢?
    
    
    生成器是一种迭代器(可以自定义的迭代器),特性:迭代一次生成一个值。
    我们得到一个生成器呢,这里有一种方式:
    定义一个函数,其内部包含有yield关键字,那么调用一下得到的结果就是生成器,并且不会执行函数内部代码
    def get():
        print(222)
        yield 2
        print('ada')
        yield 3
    
    it=get()
    print(it)#<generator object get at 0x050C3FC0>
    print(it.__next__())#222 2
    print(it.__next__())#ada 3
    print(it.__next__())#报错StopIteration

    这里我们发现当我们调用生成器it的next方法时,它遇到yield才停下来,然后把yiled后的值返回来

    继续next的话会跳到下一个yield 然后把yiled后的值返回来,若next下去的话没有yield 则会报错。

    也就是说yield后的值在调用一次next时会被返回一次。

    这样的话我们就有操作空间了,对yield后的值进行自定义我们想要的,也就是可以自定义的迭代器。

    仿写一个range的例子:

    def my_range(start,end,step=1):
        while start < end:
            yield start
            start+=step
    
    for i in my_range(0,22,3):
        print(i)

    当然yield还有其他用处,这里的yield只是提供一种自定义迭代器的方式。

  • 相关阅读:
    zoj3888 找第二大
    zoj3882 博弈
    字典树小总结
    hdu2222 字典树
    hdu1247 字典树
    开放融合 | “引擎级”深度对接!POLARDB与SuperMap联合构建首个云原生时空平台
    阿里HBase高可用8年“抗战”回忆录
    最佳实践 | RDS & POLARDB归档到X-Pack Spark计算
    今日头条在消息服务平台和容灾体系建设方面的实践与思考
    饿了么监控系统 EMonitor 与美团点评 CAT 的对比
  • 原文地址:https://www.cnblogs.com/wh-alan/p/9293165.html
Copyright © 2020-2023  润新知