• Python高级篇(08):生成器


    一、生成器定义和作用

    1. 定义:Python中,一边循环一边计算的机制,生成器对象也是迭代器对象,支持for循环、next()方法…等。
    2. 作用:循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间
    3. 意义:有一系列数要生成,如果能用生成器实现,可以提高效率

    二、生成器创建方法

    1、简单生成器:将列表推导式的[ ]改为()

    1. # 列表生成式
    2. _list = [i for i in range(10)]
    3. print(type(_list)) #
    4. print(_list) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    5. # 生成器
    6. _generator = (i for i in range(10))
    7. print(type(_generator)) #
    8. print(_generator) # at 0x7fbcd92c9ba0>
    9. # 生成器对象取值
    10. print(f"第一次迭代数据是:{_generator.__next__()}") # 第一次迭代数据是:0
    11. print(f"第二次迭代数据是:{next(_generator)}") # 第二次迭代数据是:1
    12. # 注意从第三个元素开始了!
    13. for x in _generator: # for循环只能隐式的触发了StopIteration异常,就终止迭代了,但是在程序中不会显示出来
    14. print(x) # 2,3,4,5,6,7,8,9

    2、函数对象生成器:使用yield关键字,函数就变成了一个generator

    • yield和return语句使用方法类似,但是普通函数运行到return语句则直接返回代码不再执行;而生成器对象会运行到yield后返回,再下次调用next(),会从yield语句后继续执行。
    1. def gen_generator():
    2. yield "start"
    3. for i in range(2):
    4. yield i
    5. yield "end"
    6. gen = gen_generator()
    7. print(f"从gen对象取到的第一个值为:{next(gen)}") # 从gen对象取到的第一个值为:start
    8. print(f"从gen对象取到的第二个值为:{next(gen)}") # 从gen对象取到的第二个值为:0
    9. print(f"从gen对象取到的第三个值为:{next(gen)}") # 从gen对象取到的第三个值为:1
    10. print(f"从gen对象取到的第四个值为:{next(gen)}") # 从gen对象取到的第四个值为:end
    11. # print(f"从gen对象取到的第五个值为:{next(gen)}") # 抛出StopIteration异常
    12. # 等同于
    13. gen2 = (i for i in ["start", 0, 1, "end"])
    14. for v in gen2:
    15. print(v)

     三、yield生成器高级应用

    send()概念:暂时保留先不进行,等待需要时再进行。作用与next()作用相似。

    send()使用:传递值给yield返回(可以指定yield想返回啥就返回啥),如果传None,则等同于next(generator)。

    • send()和next()区别:
      • send(value)可以值传递给yield。
      • next()不能传递特定的值,只能传递generator进去。

    使用send():

    1. def genterator_test():
    2. while True:
    3. print("--1-")
    4. num = yield 100 # 需要send传递值才能有num
    5. print("--2--", "num=", num)
    6. g = genterator_test()
    7. # 等同于next(generator)
    8. print(g.send(None)) # --1-
    9. # 100
    10. # 给上一次挂起的yield设置返回值
    11. print(g.send(11)) # --2-- num= 11
    12. # --1-
    13. # 100
    14. # 给上一次挂起的yield设置返回值
    15. print(g.send(22)) # --2-- num= 22
    16. # --1-
    17. # 100
    • 第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,可以看到,can't send non-None value to a just-started generator因为生成器just-started generator,是没有Python yield语句来接收这个值的。 

    使用next():

    1. def genterator_test():
    2. while True:
    3. print("--1-")
    4. num = yield 100 # 需要send传递值才能有num
    5. print("--2--", "num=", num)
    6. g = genterator_test()
    7. print(next(g)) # 第一次调用next,跑到 yield 100,遇到yield,执行结束。结果是:--1- 100
    8. print(next(g))
    9. """
    10. 第二次调用next,继续从上一次状态继续执行,此时,需要注意,
    11. 我们执行的起点是:num = yield 100,并且这个num值并不是100,而是通过send()传递过来的值,
    12. 即:n = send(),但是我们没有调用send()方法,所以,num自然而然为None,
    13. 所以,此时是执行print(next(g)),结果是:--2-- num= None --1- 100
    14. """

    四、yield和yield from区别

    • yield 一次只会返回一个元素,即使返回的元素是个可迭代对象,也是一次性返回
    • yield from提供一个数据传输的管道,后面加的生成器函数对象,调用方是通过这个 “包装函数” 来与生成器进行交互的,即“调用方——>委托生成器——>生成器函数”
    1. # yield
    2. def gen_generator2():
    3. yield [1, 2, 3]
    4. s = gen_generator2()
    5. print(next(s)) # [1, 2, 3]
    6. # print(next(s)) # StopIteration
    7. # yield from
    8. def gen_generator3():
    9. yield from [1, 2, 3]
    10. s1 = gen_generator3()
    11. print(next(s1)) # 1
    12. print(next(s1)) # 2
    13. print(next(s1)) # 3

  • 相关阅读:
    dd命令用法学习,是一个功能强大的工具
    图书管理系统
    Python基础篇(07):高阶函数lambda、zip、map、filter、reduce和函数注解
    MVC第三波书店登录
    [ Shell ] 通过 Shell 脚本导出 GDSII/OASIS 文件
    【C++】神奇字符串(力扣481)
    有效管理token,充分发挥ChatGPT的能力
    【产研测类】线上问题处理机制
    我看世界杯
    Vue生命周期--Vue实例创建过程详解
  • 原文地址:https://blog.csdn.net/qq_23440467/article/details/133967131