zoukankan      html  css  js  c++  java
  • 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。
  • 相关阅读:
    python读写操作(txt, mat, xls, etc文件)
    开发linux版QQ就是支持未来的国产操作系统
    为知笔记linux绿色版的快速调用
    数学物理中的常见误区
    markdown语法小结
    信息爆炸时代的知识获取
    matlab: 数据的读写
    APS期刊投稿准备: REVTex格式
    markdown基本语法
    常见的数学关系
  • 原文地址:https://www.cnblogs.com/xjmlove/p/10337607.html
Copyright © 2011-2022 走看看