zoukankan      html  css  js  c++  java
  • Python 生成器相关知识

    Python 生成器相关知识

    1. 生成器

      • 生成器概念:

        在Python社区,大部分人把生成器与迭代器看成是一种。生成器的本质就是迭代器。

        唯一区别:生成器是我们自己用Python代码构建的数据结构。迭代器都是系统提供的,或者转化得来的。

      • 获取生成器的三种方式:

        • 生成器函数:

          yield:只要函数中有yield,那么它就是生成器函数而不是一般的函数了。生成器函数中可以存在多个yield,一个yield对应一个next。yield不会结束函数

          return:函数中只存在一个return,遇到next即结束函数,并为执行者提供一个返回值。

          def func():
              a=22
              yield a
              b=12
              yield b
              c=a+b
              yield c
          ret=func()
          print(next(ret))	# yield返回值可以使用next方法逐个提取
          print(next(ret))	# 每次运行只运行到当前的yield即停止
          print(next(ret))
          22
          12
          34
          
          • 生成器函数的应用:

            其实是对数据的一种构造方法
            1. 吃包子例子:预订5000个包子,一次生全部生产出来占地方(内存),还有吃不完的浪费;如果使用生成器,那么就相当于生产一个吃一个,不会产生浪费不占地方,节省资源。
            2. 鸡蛋例子:家里需要5000个鸡蛋,有两种方法可以获取,一种是去菜场或超市直接购买5000个回来,用篮子装着放家里,占地方还怕吃不完坏掉了;第二种方法是去买个生蛋的母鸡,只要它活着就能一直生蛋,要几个就让它生几个。
          • 程序举例:

            def func():  # 这个函数就好比直接一次性生产5000个包子,生产出来的包子都在列表中,
                list1 = []  # 占用大量内存,如果数据量过大,则导致运行速度下降甚至撑爆内存。
                for i in range(1, 5001):
                    list1.append(f'第{i}个包子')
                return list1
            print(func())
            
            def gen_func():  # 使用生成器函数生产包子
                for i in range(1, 5001):  # 也是可以生产5000个,但并不是一次性返回
                    yield f'第{i}个包子'  # yield配合for循环也是可以使用,next一次提取一个数据
            baozi = gen_func()  # 调用函数,将返回值放到baozi变量中
            for i in range(1000):  # 可以根据需要的数量产生,这次需要1000个包子
                print(next(baozi))  # next1000次就可以获得
            
          • yield form

            前面用到的yield都是在函数内返回一个不可变数值,但如果想next一次就返回可迭代对象中的一个元素,就需要用到yield form。举例如下:

            def func():
                list1 = [1, 2, 3, 4, 5, 6]  # 返回的对象是个列表
                yield from list1  # 如果不用yield form将返回整个列表
            ret = func()
            for i in range(3):    # 循环3次,返回列表中的前3个数据
                print(next(ret))
            
        • 列表推导式和生成器表达式:

          • 列表推导式:用一行代码构建一个比较复杂、有规律的列表。

            列表推导式分成两种模式:

            1. 循环模式:[变量(加工后的变量) for 变量 in iterable]

              例一:一行代码实现for循环产生有规律的列表

              list1=[i for i in range(1,11)]
              print(list1)
              >>>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
              

              例二:将10以内所有整数的平方放入列表

              pflist=[i**2 for i in range(1,11)]
              print(pflist)
              >>>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
              

              例三:将50以内所有偶数放入列表

              list1=[i for i in range(2,51,2)]
              print(list1)
              

              例四:从Python1期到Python100期写入列表。

              list2=[f'Python{i}期' for i in range(1,101)]
              print(list2)
              
            2. 筛选模式:[变量(加工后的变量) for 变量 in iterable if 条件]

              在循环模式下,满足条件的放入列表

              例一:30以内能被3整除的数放入列表

              list1 = [i for i in range(1, 31) if i % 3 == 0]
              print(list1)
              >>>[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
              

              例二:过滤掉长度小于3的字符串列表,并将剩下的转换成大写

              l1 = ['abc', 'a', 'h', 'inter', 'amwk', 'ce', 'sk', 'at', 'apple', 'c', 'reset']
              print([i.upper() for i in l1 if len(i) >= 3])
              >>>['ABC', 'INTER', 'AMWK', 'APPLE', 'RESET']
              

              例三:含有两个'e'的所有的人名全部大写留下来

              names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
                       ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
              print([name.upper() for i in names for name in i if name.count('e')==2])
              >>>['JEFFERSON', 'WESLEY', 'STEVEN', 'JENNIFER']
              
          • 生成器表达式:
            生成器表达式与列表推导式的写法几乎一模一样:只是将列表推导式中的方括号变成了圆括号,生成器的最大优点是节省资源。

            生成器表达式也分为循环模式和筛选模式,支持多层循环构建,写法上只有一个不同:[]换成()。虽然只是写法不同,但是本质有很大区别,列表推导式非常占用内存,生成器表达式非常节省内存。

            obj= (i for i in range(0,11, 2))
            print(next(obj))
            print(next(obj))
            print(next(obj))
            for i in obj:
                print(i,end='  ')
            >>>0
            2
            4
            6  8  10  
            
          • 两种表达式的总结:

            1. 列表推导式:

              缺点:

              • 有毒,列表推导式只能构建比较复杂并且有规律的列表,不要太着迷。
              • 超过三层循环才能构建成功的列表,就不建议用列表推导式。
              • 排错不行,查找错误(debug)下不方便,不直观。

              优点:

              • 一行构建,简单
              • 装逼?(太白这样觉得)
            2. 生成器表达式:
  • 相关阅读:
    checkedListBox的具体用法
    pi
    从1.9G到64K
    世界编程大赛第一名程序
    SQLServer中导入/导出Excel的基本方法
    Android 内存优化测试
    android,内存优化详解
    Android解决大图片内存溢出
    Android有效解决加载大图片时内存溢出的问题
    android端读取本地图片出现OutOfMemoryException
  • 原文地址:https://www.cnblogs.com/amwkvi/p/14078347.html
Copyright © 2011-2022 走看看