• 003---生成器 & 迭代器


    生成器 & 迭代器

    列表生成式

    现在有个需求,列表[1, 2, 3, 4, 5, 6, 7, 8, 9],将列表里的每个值加1。

    • 二逼青年版
    
    a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    b = []
    for item in a:
        b.append(item + 1)
    a = b
    print(a)
    
    • 普通青年版
    a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    for index, ele in enumerate(a, 0):
        a[index] += 1
    
    print(a)
    
    • 文艺版(lambda + map 搭配使用)
    a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    a = list(map(lambda x:x+1,a))
    print(a)
    
    
    • 装逼青年版
    a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    print([i + 1 for i in a])
    
    • 这种写法就是列表生成式
    • 习题:利用列表生成式一行代码实现9 * 9乘法表
    print('
    '.join([''.join(['%d * %d = %-3d' % (i, j, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))
    

    生成器

    • 通过列表生成式,可以直接创建一个列表,但是毕竟内存有限,列表的容量也是有限的。创建一个包含100万个元素的列表,但是我们仅仅需要访问前面几个元素,这就造成了内存大量白白浪费。
    • 在python中有一种更好的解决方式,边循环边计算的机制。称为(generator)
    • 简单创建生成器(只需要把列表生成器的方括号改成括号)
    g = (i for i in range(5))
    
    print(type(g),g.next())
    
    • next()取值和for循环取值
    # 使用next()取值
    g = (i for i in range(5))
    print(type(g))
    print('开始取值')
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    # print(next(g)) # 报错:StopIteration,因为取不到值了
    
    # 基本上不会使用next(),正确应该使用for循环。而且还不需要担心会报错。拿不到函数return返回值
    g = (i for i in range(10))
    for i in g:
        print(i)
    
    • 斐波拉契
    # 斐波拉契:1 1 2 3 5 8 13 21
    def fbi(num):
        n, a, b = 0, 0, 1
        while n < num:
            yield b  # # 到这停止,可以理解为冻结当前代码。并且,把值返回给外面的next()
            print(a, b)
            a, b = b, a + b
            n += 1
    
    
    for i in fbi(2):
        print(i)
    
    • 代码解析:

      • return 和 yield 的区别
        • 返回并终止函数
        • 返回数据,并冻结当前的执行过程。
        • next()唤醒冻结函数的执行过程,继续执行,直到遇到下一个yield
      • 函数加了yield之后
        • 函数()就得到了生成器,不next()不开始执行。
        • return 在生成器里,代表生成器的终止,直接报错
    • 深入

    # 生成器send,相当于唤醒。
    def work(n):
        count = 0
        while count < n:
            count += 1
            sign = yield count
            print('sign的值:',sign)
            if not sign:
                yield count + 2
    
    
    new_range = work(4)
    # res = next(new_range)           # 开始第一次取值 拿到一个1
    # print(res)                      # 1
    # res1 = new_range.send(True)     # 第二次取值 发送一个true  函数遇到true 循环
    # print(res1)                     # 2
    # res2 = new_range.send(False)    # 第三次取值 n=3
    # print(res2)
    
    

    迭代器

    • 可以作用for循环的类型:

      • 集合类型:str、list、tuple、dict、set
      • generator:生成器和带yield的函数

      这些类型称为可迭代对象:iterable

      from collections import Iterable
      
      print(isinstance([],Iterable))
      print(isinstance('',Iterable))
      print(isinstance({},Iterable))
      print(isinstance(set(),Iterable))
      print(isinstance((i for i in range(2)),Iterable))
      
      
    • 生成器不仅可以作用域for还可以被next()不断取值,直到没有数据可取

    from collections import Iterator
    print(isinstance((i for i in range(2)),Iterator))
    

    总结

    • 凡是可以作用于for循环的对象都是可迭代对象,Iterable
    • 凡是可以作用于next()的对象都是迭代器,Iterator
    • 集合数据类型虽然不是迭代器,但是可以通过iter()函数变成Iterator。
  • 相关阅读:
    Java中怎么控制线程訪问资源的数量
    我的Hook学习笔记
    《编写可读代码的艺术》——简单总结
    Hdu 1016 Prime Ring Problem (素数环经典dfs)
    setsockopt()使用方法(參数具体说明)
    Html5培训之精髓
    [unity3d]unity平台的预处理
    音频编辑大师 3.3 注冊名 注冊码
    linux tar.gz zip 解压缩 压缩命令
    面向对象的三个基本特征
  • 原文地址:https://www.cnblogs.com/xjmlove/p/10337607.html
Copyright © 2020-2023  润新知