zoukankan      html  css  js  c++  java
  • 迭代器和生成器

    可迭代协议:

       含有双下方法__iter__的对象就是可迭代对象。

    迭代器协议:

       同时含有__iter__和__next__方法的对象就是迭代器。

    print(dir([])) #列表内置的方法
    print(dir([].__iter__())) #__iter__中内置的方法
    print(set(dir([].__iter__())) - set(dir([])))#将得到的方法列表转换成集合,相减得到__iter__方法中独有的内置方法
    print(dir([]).__iter__()) #一个可迭代对象加上__iter__方法就是迭代器
    print(({}).__iter__()) #字典也是如此

    打印截图:

    例:

    i = [1,2,3,4,5,6,7,8,9,10,11,12,13]
    ix = i.__iter__()
    print(ix.__length_hint__()) #打印这个可迭代对象中的元素个数
    print(ix.__setstate__(3)) #指定开始打印位置,参数为下标,返回值为None
    print(ix.__next__())#一条一条打印,这里为4
    print(ix.__next__())#5
    print(ix.__next__())#6
    for s in ix: #内存已经读取列表所有元素,但是从7开始,证明读取一个元素之后,该元素会从内存中释放,也就是说,迭代器读取数据的方式是一条一条的读(读完一个释放一个)
        print(s)#7,8,9,10,11,12,13

    # print(ix.__next__())#报错 数据已经读取完毕,内存被释放,读不到数据 #打印: 13 None 4 5 6 7 8 9 10 11 12 13

     结论:

    1、__iter__方法中独有三个内置方法,__length_hint__,__next__,__setstate__。分别的作用是,查看元素的个数,一条一条打印,从哪个位置打印
    2、含有__iter__方法的对象就是可迭代对象(可迭代协议)
    3、同时含有__iter__方法和__next__方法,那么它就是迭代器(迭代器协议)
    4、__iter__方法中包含__next__方法,但不是在同一个层级当中,所以只有__iter__方法不是迭代器,仅仅是一个可迭代对象
    5、当一个可迭代对象引用了__iter__方法时,那么这个对象就是迭代器
    6、迭代器读取数据的方式可以是用__next__一条一条的读,读取一个元素之后,该元素会从内存中释放,也就是说,迭代器读取数据的方式是一条一条的读(读完一个释放一个),当数据读完还要读取时会报错

    迭代器的好处:
      
    从容器类型中一个一个的取值,会把所有的值都取到。
      节省内存空间,迭代器并不会在内存中再占用一大块内存,而是随着循环每次生成一个;每次next每次给我一个



    生成器函数和生成器:
    def generator():
        print('a')
        yield '1'
        print('b')
        yield '2'
        print('c')
        yield '3'
        print('d')
        yield '4'
    
    
    print(generator().__next__())#函数调用后返回一个生成器,直接执行生成器:1
    print(generator().__next__())#每次调用函数都会返回一个新的生成器:1
    print(generator().__next__())#每次调用函数都会返回一个新的生成器:1
    
    g = generator() #函数调用后返回一个生成器,把它赋值给g,生成一个新的生成器g
    print(g) 新的生成器的地址
    print(g.__next__())#获取生成器g的数据:1
    print(g.__next__()):#2
    print(g.__next__()):#3
    
    
    #打印:
    a
    1
    a
    1
    a
    1
    <generator object generator at 0x000001D03DBCDB48>
    a
    1
    b
    2
    c
    3
    结论:
      含有yield关键字的函数都是生成器函数,且不能和return一起使用,且需要写在函数体内。yield也可以设置返回值,执行yield后并不会结束程序
      生成器是一个迭代器,生成器函数调用后会返回一个生成器,此时并不会执行函数体内的程序。当把这个生成器重新赋值给一个对象时,会形成一个新的生成器,
    执行生成器时,才会执行函数体内的程序。每次调用生成器函数都是返回一个新的生成器,所以不创建对象进行接收生成器时,直接打印是无法获取全部的数据。


    send方法:
    def generator():
        print('a')
        b = yield 1
        print('b',b)
        yield 2
        print('c')
        yield 3
        print('d')
        l = yield 4
        print(l)
    
    g = generator()
    # print(g.send(111))#报错,因为此时没有对应的yield能够接收参数
    # print(g.send(None))#不报错,传参值设置为空时,程序直接向下执行
    print(g.__next__())#此时程序停在yield 1
    # print(g.send(None))
    # print(g.send()) #报错
    print(g.send('这是一条被send传过来的参数'))#执行到这里时,传入的字符串被yield 1接收,赋值给b,程序继续向下执行,打印字符串b,调用b,继续向下执行,返回yield的数据2
    print(g.__next__())
    print(g.__next__())
    #print(g.send(111))#报错,传入的参数被yield 4接收,但下方已经没有数据可供读取
    
    
    #打印:
    a
    1
    b 这是一条被send传过来的参数
    2
    c
    3
    d
    4
    
    
    
    结论:
    send与next的作用一样,会返回一条数据,且send支持传参:
    send不传参会报错,传的参数被上一个yield接收,然后程序继续向下执行,继续返回一条数据。
    获取生成器第一条数据不能使用send进行传参,因为没有对应的yield可以接收参数,传参值设置为None时,程序直接向下执行,不报错。
    获取生成器最后一条数据之后使用send进行传参同样会报错,传入的参数被yield接收,但数据已经读取完毕,没有多余的数据能够读取,但传入的参数有效。



     
     
    
    
    
     
      
     
  • 相关阅读:
    做到就得到,人生成功的启示
    这个世界没什么过不去的事情,记我的经历
    要想富,先读书,没有文化要吃一辈子的亏
    git学习笔记11-git多人协作-实际多人怎么开发
    git学习笔记10-新开发的功能不想要了-强行删除分支
    git学习笔记09-bug分支-自己的分支改到一半了-要去改bug怎么办?
    git学习笔记08-分支管理策略-实际上我们应该怎么应用分支
    git学习笔记07-冲突了怎么办-那就解决冲突呗
    git学习笔记06-创建分支合并分支-比svn快多了,因为只有指针在改变
    git学习笔记05-从远程库克隆
  • 原文地址:https://www.cnblogs.com/aizhinong/p/11374011.html
Copyright © 2011-2022 走看看