• Python 生成器 (generator) & 迭代器 (iterator)


    python 生成器 & 迭代器

    生成器 (generator)

    列表生成式

    列表生成式用来生成一个列表,虽然写的是表达式,但是储存的是计算出来的结果,因此生成的列表受到内存大小的限制
    示例:

    a = [x ** 2 for x in range(5)]
    print(a)
    

    输出结果:

    [0, 1, 4, 9, 16]
    

    生成器 (generator)

    生成器同样可以用来生成一个列表,但是生成器保存的是算法,在每一次调用 next 时才会计算出结果,因此生成的列表不会受到内存大小的限制
    示例:

    a = (x ** 2 for x in range(5))
    print(a)
    for i in range(6):
    	print(next(a))
    

    输出结果:

    <generator object <genexpr> at 0x107da7870>
    0
    1
    4
    9
    16
    Traceback (most recent call last):
      File "<stdin>", line 2, in <module>
    StopIteration
    

    每次调用 next(),就计算出下一个元素的值,无法再次获取前面元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration 的错误

    生成器函数

    当函数中出现 yield 时这个函数就成了一个 generator 的函数
    generator 在执行的时候遇到 yield 时会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行
    示例:

    def fib(max_n):
        """斐波那契数列生成器"""
        n, a, b = 0, 0, 1
        while n < max_n:
            yield b
            a, b = b, a + b
            n = n + 1
        return 'done'
    
    
    def main():
        f = fib(6)
        while True:
            try:
                x = next(f)
                print(x)
            except StopIteration as e:
                print("Generator return value:", e.value)
                break
    
    
    if __name__ == '__main__':
        main()
    
    

    输出结果:

    1
    1
    2
    3
    5
    8
    Generator return value: done
    

    通过 yield 实现在单线程的情况下实现并发运算的效果

    示例:

    import time
    
    
    def consumer(name):
        print("%s开始吃包子了" % name)    
        while True:
            produce = yield                                # 函数在此暂停,等待唤醒
            print("%s吃了第%i笼包子" % (name, produce+1))      # 唤醒后执行
    
    
    def producer(name):
        c = consumer("A")
        c2 = consumer("B")
        c.__next__()    
        c2.__next__()
        print("%s准备开始生产" % name)
        for i in range(3):
            time.sleep(1)
            print("已经做了%i笼包子" % (i+1))
            c.send(i)                                       # 将i发送给produce,并唤醒函数
            c2.send(i)
    
    producer("C")
    

    输出结果:

    A开始吃包子了
    B开始吃包子了
    C准备开始生产
    已经做了1笼包子
    A吃了第1笼包子
    B吃了第1笼包子
    已经做了2笼包子
    A吃了第2笼包子
    B吃了第2笼包子
    已经做了3笼包子
    A吃了第3笼包子
    B吃了第3笼包子
    

    在 producer 函数中 c 和 c2 轮流调用 consumer 函数
    send()next() 一样可以唤醒生成器,而且还能给 yield 传值

    迭代器 (iterator)

    可迭代对象 (iterable)

    可以直接作用于 for 循环的数据类型有以下两种:

    1. 一类是集合数据类型,如 list、tuple、dict、set、str 等
    2. 一类是 generator,包括生成器和带 yield 的 generator function
      这些可以直接作用于 for 循环的对象统称为可迭代对象

    示例:

    def fib(max_n):
        """斐波那契数列生成器"""
        n, a, b = 0, 0, 1
        while n < max_n:
            yield b
            a, b = b, a + b
            n = n + 1
        return 'done'
    
    
    def main():
        f = fib(6)
        for i in f:
            print(i)
    
    
    if __name__ == '__main__':
        main()
    
    

    输出结果:

    1
    1
    2
    3
    5
    8
    

    迭代器 (iterator)

    可以被 next() 函数调用并不断返回下一个值的对象称为迭代器
    生成器都是 Iterator 对象,但list、dict、str 虽然是 Iterable ,却不是Iterator
    把list、dict、str 等 Iterable 变成 Iterator 可以使用 iter() 函数
    示例:

    a = [1, 2, 3, 4, 5, 6, 7]
    b = a.__iter__()
    c = iter(a)
    
    print(a, b, c)
    

    输出结果:

    [1, 2, 3, 4, 5, 6, 7] <list_iterator object at 0x11d271f60> <list_iterator object at 0x11d260160>
    

    b, c 都是通过 a 变成的迭代器
    a, b, c 都可以使用 for 循环:

    for i in a:
    	print(i)
    for i in b:
    	print(i)
    

    结果一致

    对比

    生成器 (generator) 都是迭代器 (iterator),但是迭代器不一定是生成器,还有通过 iter() 变成迭代器的可迭代对象

  • 相关阅读:
    iOS之项目常见文件、UIApplication详解及UIApplicationDelegate的代理方法
    ios关于uibutton内部结构
    ios关于图片拉伸的版本间的几种方法
    uitalbview加载xib详解
    xcode4.2工程Created by名字的修改问题
    工作中常用到的测试分享工具
    IOS 分享 牛人 Demo
    ios输入内容正则表达式的应用
    ios-学习篇-归档
    IOS-网络(GCD)
  • 原文地址:https://www.cnblogs.com/dbf-/p/11877251.html
Copyright © 2020-2023  润新知