• python基础(八)-迭代器与生成器


    一、迭代器

    li=[1,2,3]
    f=li.__iter__()
    print(f)
    print(f.__next__())
    print(f.__next__())
    print(f.__next__())
    
    #运行结果
    <list_iterator object at 0x0000000000D770B8>
    1
    2
    3

    迭代器:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)

    可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)

    之前所说字符串、列表、元组、字典可迭代对象,其实是调用了__iter__方法,生成一个迭代器。

    迭代器只能往前不会后退,且遍历取值时只能取一次。

    for循环机制:

    使用for循环对序列和字典进行迭代,其实就是调用数据对象的__iter__方法,生成迭代器,然后再调用__next__方法取值,直到捕捉StopIteration异常,以终止迭代。

    二、生成器

     1、定义:

      可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象

    2、Python中生成器两种表现形式:

      生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

      生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

    3、生成器优点:

      延迟操作,是指在需要的时候才产生结果,而不是立即产生结果。这也是生成器的主要好处。

      节省内存

    生成器的唯一注意事项就是:生成器只能遍历一次

    4、生成器函数:

    def lay_eggs(num):
        for egg in range(num):
            res='蛋%s' %egg
            yield res
            print('下完一个蛋')
    
    laomuji=lay_eggs(10)#我们拿到的是一只母鸡
    print(laomuji)
    laomuji.__next__() #蛋下完 母鸡就死了

    def fun():
        print('第一次')
        res=yield 1
        print('第二次',res)
        yield 2
        print('第三次')
    
    f=fun()
    f.__next__()
    f.send('fuck you')  #一个效果跟next方法,另一个效果就是传递参数给上次yield

    两个小例子:注意取值的地方

    def test():
        for i in range(4):
            yield i
    
    g=test()
    
    g1=(i for i in g)   #g1应该是一个新的生成器
    g2=(i for i in g1)
    
    print(g)
    print(g1)
    print(g2)
    print(list(g1))   #[0, 1, 2, 3]
    print(list(g2))   #[]    g2中的g1已经被上一步list取完,此处执行list没有值可取
    有点绕的例子一
    def add(n,i):
        return n+i
    
    def test():
        for i in range(4):
            yield i
    
    g=test()   #[0,1,2,3]
    for n in [1,10]:    # n=1  g=[1,2,3,4] ; n=10 g=[11,12,13,14]
        g=(add(n,i) for i in g)
        print('for',n,g)
    
    print(g)
    print(list(g))  # [20, 21, 22, 23] 为什么是这个呢?
    
    # 过程:1、生成器g 2、for循环列表[1,10] 又是个生成器g-->覆盖之前的g 3、最终生成一个g=(add(10,))
    # g=[0,1,2,3]  => for循环 n=1  g=[1,2,3,4] ; n=10 g=[11,12,13,14]
    比较绕的例子二
    def add(n,i):
        return n+i
    
    def test():
        for i in range(4):
            yield i
    
    g=test()   #[0,1,2,3]
    for n in [1,10]:    # n=1  g=[1,2,3,4] ; n=10 g=[11,12,13,14]
        g=(add(n,i) for i in g)
        print('for',n,g)
    
    print(g)
    print(list(g))  # [20, 21, 22, 23] 为什么是这个呢?
    
    # 过程:1、生成器g 2、for循环列表[1,10] 又是个生成器g-->覆盖之前的g 3、最终生成一个g=(add(10,))
    # g=[0,1,2,3]  => for循环 n=1  g=[1,2,3,4] ; n=10 g=[11,12,13,14]
    例二的错误解析
    def add(n,i):
        return n+i
    
    def test():
        for i in range(4):
            yield i
    
    g=test()   #代码执行,生成一个生成器 [0,1,2,3]  
    for n in [1,10]:     #代码也执行 n= 1
        g=(add(n,i) for i in g)  # 第一次循环:全局变量n=1,生成新的生成器 g=((add(n,i) for i in test()))
                                #第二次循环:n=10,生成新的生成器 g=(add(n,i) for i in ((add(n,i) for i in test())))
    
    # 代码执行到这里:全局变量 n = 10
    
    # 如果对生成器 g 取值:执行 __next__() 方法 --> n =10,g=(add(n,i) for i in ((add(n,i) for i in test())))
    # 类似于 递归 
    # print(list(g))
    例二的正确解析姿势
  • 相关阅读:
    Dr.Watson
    得到当前操作系统的版本的
    屏蔽回车关闭对话框事件
    一个发邮件的类(用CDO实现)
    怎样配置SQL Server发送电子邮件
    无进程DLL木马的又一开发思路与实现
    Write AutoUpdating Apps with .NET and the Background Intelligent Transfer Service API
    WINDOWS编程入门一个初级问题的分析
    智能客户端技术总结(一)
    【.NET】C#.NET ADO.NET数据访问模型概述
  • 原文地址:https://www.cnblogs.com/chenzhuo-/p/6148181.html
Copyright © 2020-2023  润新知