Python-列表推导式、生成器-Python自学笔记5

本章重点

  • 列表生成式
    • 循环模式
    • 筛选模式
    • 嵌套模式
  • 生成器
    • 什么是生成器
    • 生成器的特点是什么
    • 怎么创建一个生成器
    • 生成器表达式
    • 生成器的优点

列表推导式

列表推导式就是for循环的简写,能生成比较复杂但是有规律的列表

列表推导式有三种模式分别是 循环模式 筛选模式 嵌套模式

  • 循环模式

    • [最终结果 for 每次遍历获得的元素 in 需要遍历的对象]

    • 实例:

    • li = [num for num in range(0, 101)]  # 这是列表推导式
      
      # 相当于
      # li = []
      # for num in range(0, 101):
      #     li.append(li)
      
    • 结果:print(li)

    • [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
      11, 12, 13, 14, 15, 16, 17, 18, 19, 
      20, 21, 22, 23, 24, 25, 26, 27, 28, 
      29, 30, 31, 32, 33, 34, 35, 36, 37, 
      38, 39, 40, 41, 42, 43, 44, 45, 46,
      47, 48, 49, 50, 51, 52, 53, 54, 55,
      56, 57, 58, 59, 60, 61, 62, 63, 64, 
      65, 66, 67, 68, 69, 70, 71, 72, 73,
      74, 75, 76, 77, 78, 79, 80, 81, 82, 
      83, 84, 85, 86, 87, 88, 89, 90, 91,
      92, 93, 94, 95, 96, 97, 98, 99, 100]
      
  • 实例2:

  •  s1 = "abcdefg"
    str_list = [s.upper() for s in s1]  # 我们可以操作最终结果,让最终结果成为我们想要的样子,这里我想让最终结果每一个都是大写
      # 相当于
      # str_list = []
      # for s in s1:
      #     str_list.append(s.upper())
    
    • 结果:['A', 'B', 'C', 'D', 'E', 'F', 'G']

    总之列推导式不需要去死记硬背,只需要多敲几遍就熟悉了。

  • 筛选模式

    • [最终结果 for 每次遍历获得的元素 in 需要遍历的对象 筛选条件]

    • 实例:

    • # 目标 获取 1到100的所有偶数并添加到列表里
      li = [num for num in range(1, 101) if num % 2 == 0]
      
    • 结果:print(li)

    • [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 
      22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 
      42, 44, 46, 48, 50, 52, 54, 56, 58, 60,
      62, 64, 66, 68, 70, 72, 74, 76, 78, 80,
      82, 84, 86, 88, 90, 92, 94, 96, 98, 100]
      
  • 嵌套模式

    • [最终结果 for 外层遍历获得的元素 in 外层遍历对象 for 内层遍历获得的元素 in 外层遍历获得的元素]

    • 实例:

    •   # 目标遍历[[1, 2, 3, 4], [5, 6], [7, 8, 9, 0]]获得里面的元素并添加到新列表
        l = [[1, 2, 3, 4], [5, 6], [7, 8, 9, 0]]
        li = [num for i in l for num in i]
        # 相当于
        # for i in l:  外层循环
        #     for num in i:  内层循环
        #         li.append(num)  将每次遍历获得的元素添加到指定列表里
      
    • 结果:print(li)

    •   [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
      
    • 嵌套模式也支持筛选

    • 实例2:

    • # 目标将s_list列表中包含Python的字符串添加到新列表里,并且全部转为大写
      s_list = [['Pythonacbdef', 'asdasPython', 'abc'], ['sffsdopython', 'sdasd'], ['psasdnodython', 'cdf', 'pythonnb']]
      new_list = [s.upper() for l in s_list for s in l if 'PYTHON' in s.upper()]
      # 相当于
      # for l in s_list:  # 遍历外层列表
      #     for s in l:  # 遍历大列表内的小列表
      #         if 'PYTHON' in s.upper():  # 这里的upper是无视大小写判断字符串里是否存在PYTHON, 与转换结果的大写无关
      #             new_list.append(s.upper())  # 将存在python的字符串转换成大写追加进新列表里
      
    • 结果:print(new_list) >>> ['PYTHONACBDEF', 'ASDASPYTHON', 'SFFSDOPYTHON', 'PYTHONNB']

    • 可能有点绕,我画了个图将列表推导式里的段代码与for 循环一一对应的标注了出来,稍微看一下就好,具体还得自己多敲几遍,实践是理解的最好办法。比如给自己制定点题目,如何自己尝试使用列表推导式解出来。

    • image-20210328214314639

生成器

什么是生成器

生成器是一直特殊的迭代器,迭代器能做的事生成器也能做,生成器本质上就是迭代器,只不过生成器的编写方式和表现形式不一样,迭代器是由可迭代对象转换而来,生成器是我们自己用生成器函数或生成器表达式创建出来的。迭代器能做的事情生成器全部能做到,且特性也与迭代器一样,不能直接查看生成器里的元素,需要使用next()进行取值,在没有后续元素时,继续next()也会和迭代器一样抛出一个 StopIteration 异常。

生成器的特点是什么

生成器的特点也和迭代器一样,只能遍历一次,每次只取一个元素,当取下一个元素时本次占用内存的元素就会被清除,也就是说在同一时间里只占用一小块内存,生成器的元素用完即清除,非常节省内存。

怎么创建一个生成器

创建生成器有两种方法,分别是 生成器函数 生成器表达式

  • 生成器函数

    1. 生成器函数的写法跟我们函数的写法几乎一模一样,不同的是函数返回值使用的是return 并且在使用后就退出函数了,且生成器函数和函数的执行顺序也不一样,这个后面会说到,先看看怎么写一个生成器吧

    2.  def gene():
      """生成器"""
      li = [1, 2, 3]
      # 假设此处如果是 yield li 那么使用生成器对象取值,取到的就是整个列表[1, 2, 3]
      for i in li:
          yield i
       gene_obj = gene()  # 获取生成器对象
       print(next(gene_obj))  # 生成器不能直接查看元素需要进行next取值
       print(next(gene_obj))
       print(next(gene_obj))
      
    3. 结果:

    4.  1
       2
       3
      
    5. 假设我们在上面print(next(gene_obj))后再 print(next(gene_obj)) 一下看看会怎么样

    6. 结果:

    7.  Traceback (most recent call last):
       File "C:/Users/xxxx/xxxx/xxxx/xxxx.py", line 10, in <module>
       print(next(gene_obj))
       StopIteration
      
    8. 前面提到了生成器和迭代器一样,取值次数超过元素总个数,就会抛出StopIteration异常

  • 生成器函数 yield from 使用方法

    1. 还是拿上面的例子举例
  def gene():
      li = [1, 2, 3]
      # yield from li 就是每次使用next取值一次就返回列表的一个元素
      yield from li  # 可以代替 for i in li  简化代码增加代码的可读性
  gene_obj = gene()  # 获取生成器对象
  print(next(gene_obj))  # 生成器不能直接查看元素需要进行next取值
  print(next(gene_obj))
  print(next(gene_obj))
    """
  结果:
  1
  2
  3
  """
  • 生成器对象也是一个可迭代对象,可以使用前面提到的 print('__iter__' in dir(gene_obj))查看,是可迭代对象就意味着可以使用for 进行取值

  • 尝试一下

  • def gene():
        """生成器"""
        li = [1, 2, 3]
        yield from li
        
    gene_obj = gene()  # 获取生成器对象
    for i in gene_obj:
        print(i)
    
  • 结果:

  • 1

  • 2

  • 3

  • 生成器函数的执行顺序

    • 生成器的工作顺序就是 遇到yield 就保存状态 返回元素 --- 再次next() 回到上次保存状态的位置继续往下执行 一直按照这两个状态运行,直到生成器内没有元素可取了,生成器的使命也就完成了。

    • 也就是说生成器函数的执行顺序是遇到 next() 执行 执行到 yield 返回元素并保存状态,可以理解为代码停留在yield的下一行,但是不执行,等到下一次next() 就从上一次停留的位置进行往下执行

    • image-20210329135945066

    • 像上图中的代码运行结果是

    • 1
      我执行了没有 1 
      2
      我执行了没有 2 
      3
      
  • 生成器表达式

    1. 生成器表达式与列表推导式的写法几乎一模一样

      • 列表推导式: [最终结果 for 每次遍历获得的元素 in 需要遍历的对象]
      • 生成器表达式:(最终结果 for 每次遍历获得的元素 in 需要遍历的对象)
      • 对的只是中括号换成了小括号
    2. 实例:

      • gene_obj = (i for i in range(0, 4)) 这样我们就获得了一个生成器对象

      • # 来next()一下这个生成器对象
        print(next(gene_obj))
        print(next(gene_obj))
        print(next(gene_obj))
        """
        结果:
        0
        1
        2
        """
        
      • 从上面的代码我们可以看出来,生成器还有另外一个好处就是,它只在你需要的时候从产生一个元素,可以实现一边循环一边计算,并不会一次性生成所有结果,也就避免了爆内存的情况出现。

      • 一直都说生成器节省内存,但是大家都没有什么直观的感受,下面来两段代码可以打开终端窗口 输入 python 体验一下(可以按 ctrl + C 终止程序)

        • sum([i**i for i in range(0, 1000000)])
        • sum((i**i for i in range(0, 1000000)))
        • image-20210329142354089
        • 我们可以看到用列表表达式的内存占用还在随着程序的运行而增加,而生成器的内存占用一直很低。
        • image-20210329142603661
  • 生成器优缺点

    • 优点
      1. 节省内存,这是生成器最大的优点没有之一
      2. 延迟计算,一次返回一个结果。
      3. 增加代码可读性(这个我觉得看个人吧)
    • 缺点:
      1. 生成器对象只能遍历一次
      2. 时间上的消耗会稍微多一点(用时间换空间嘛)
  • 总结:

    • 生成器NB, Python NB

posted @   假文艺青年。  阅读(106)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示