• Python 生成器


    什么是生成器:

    • 生成器是 Python 中的一个对象(按照某种规律,来生成元素的对象),生成器不是列表,保存了产生元素的算法,同时会记录游标的位置(现在拿到第几个元素了),为了下次继续拿数据,而不是从头开始拿数据。可以通过一直调用 next() 方法获取值,这个对象不保存数据,每次调用会返回一个值,即做到了列表的好处,又不占用空间。
    • 在 Python 中,这种一边循环一边计算的机制,称为生成器:generator,生成器是在需要用到数据的时候再提供,相比列表生成器一次性生成多个数据,不占内存
    • 生成器是一个特殊的程序,可以被用作控制循环的迭代行为,Python 中生成器是迭代器的一种,使用 yield 返回值函数,每次调用 yield 会暂停,而可以使用 next() 函数和 send() 函数恢复生成器。

    生成器的创建方式:

    • 生成器表达式
      • a = (expression for iterm in iterable)
    • 生成器函数
      • 在一个普通函数中使用 yield 关键字 
        • yield 类似于 return 函数,可以将 yield 后面的对象返回,并且记住这个返回的位置,下次通过 next 迭代时,代码从 yield 的下一条语句开始执行。
    • 生成器函数内部,不允许使用 return 语句返回任何值,因为生成器函数已经默认返回一个生成器了,但是你可以只写一个 return,后面不带任何值

    生成器的取值方式:

    • 通过 next() 函数取值
    • 通过 send(value) 函数取值
      • 通过 next 和 send 函数取值时,当时取完了,会报 StopIteration 停止迭代错误
      • 第一次 send 前如果没有使用 next 函数进入生成器,则第一个 send 只能传入参数 None,send 类似于 next 可以进入生成器中去执行代码,但是 send 需要传入参数,且将传入的参数赋值给代码中的 yield 前的变量
    • 通过 for 循环取值
      • 因为生成器本身就是一个特殊的迭代器

     实例如下,定义生成器及通过 next 和 for 循环执行取值:

    1. # 第一种创建生成器的方式
    2. b = (i for i in range(5))
    3. print(b) # <generator object <genexpr> at 0x0000000000F5B360> generator 是一个生成器
    4. # print(b.__next__()) # 通过私有方法 __next__() 进入生成器中取值
    5. # print(next(b)) # 通过内置函数 next() 进入生成器中取值,依次取值,取完后再取就报迭代结束错误
    6. for x in b: # 通过 for 循环取值,生成器本身是一个迭代器,是一个可迭代对象
    7. print(x)
    1. # 第二种创建生成器的方式 通过yield创建
    2. def func():
    3. print("hello1")
    4. yield 1 # yield 类似return,具有返回值作用
    5. print("hello2")
    6. yield 2
    7. f = func()
    8. print(next(f)) # 第一次next执行到yield1 结果:hello11
    9. print(next(f)) # 第二次next从yield1开始执行,执行到yield2停止 结果:hello22
    10. # 结果如下:
    11. hello1
    12. 1
    13. hello2
    14. 2
    1. # 斐波那契数列 0 1 1 2 3 5 8
    2. def fibo(max):
    3. n, before, after = 0, 0, 1
    4. while n < max:
    5. print(after)
    6. before, after = after, before+after
    7. n += 1
    8. fibo(3)
    9. # 通过生成器计算斐波那契数列
    10. def fibo(max):
    11. n, before, after = 0, 0, 1
    12. while n < max:
    13. yield after
    14. before, after = after, before+after
    15. n += 1
    16. f = fibo(3)
    17. for i in f:
    18. print(i)
    19. # 结果如下
    20. 1
    21. 1
    22. 2

     实例如下,定义生成器及通过 send 执行取值:

    1. # send()函数
    2. def func():
    3. print("hello1")
    4. count1 = yield 1
    5. print(count1)
    6. print("hello2")
    7. count2 = yield 2
    8. print(count2)
    9. yield 3
    10. f = func()
    11. # print(f.next())
    12. # || 上下两行代码相等
    13. print(f.send(None)) # 第一次send()前如果没有next(),只能传入一个None,send类似与next可以进入生成器中去执行代码,但是send需要传入参数,且传给代码中yeild前的变量count1
    14. print("--------------")
    15. print(f.send("world1"))
    16. print("--------------")
    17. print(f.send("world2"))
    18. # 结果如下
    19. hello1
    20. 1
    21. --------------
    22. world1
    23. hello2
    24. 2
    25. --------------
    26. world2
    27. 3
  • 相关阅读:
    面向对象编程三⼤特性 --封装、继承、多态
    2023前端面试整理
    Android TextWatcher 避免死循环
    vm_flutter
    用于工业物联网和自动化的 Apache Kafka、KSQL 和 Apache PLC4
    Linux 虚拟机内挂载 iso 文件
    鏖战 Web 性能优化:HTTP
    gpu cuda 矩阵乘法
    Python读取复杂电子表格(CSV)数据小技巧一则
    【Linux】操作系统以及虚拟机的安装与配置
  • 原文地址:https://blog.csdn.net/Mark_Zhengy/article/details/127631207