• python生成器总结


    生成器的概念

    一句话解释:包含了yield关键字的函数就是生成器,它的返回值是一个生成器对象

    Python 中的生成器(Generator)是十分有用的工具,它能够方便地生成迭代器(Iterator)。

    创建以及使用

    1. def my_gen():
    2. yield 1
    3. yield 2
    4. yield 3
    5. gen = my_gen()
    6. #生成器可以由next()调用
    7. while True:
    8. try:
    9. next(gen)
    10. except StopIteration:
    11. print('Done..')
    12. break
    13. #next() 调用太啰嗦,通常我们用迭代的方式获取生成器的值:
    14. gen = my_gen()
    15. for item in gen:
    16. print(item)

    生成器还有一种更简单的写法,像这样: 

    1. # 列表推导式
    2. my_list = [x for x in range(10000)]
    3. # 生成器表达式
    4. my_gen = (x for x in range(10000))

     yield的理解

    1.yield相当于return。
    2.函数遇到yield就暂停,保存当前信息,返回yield的值。
    3.在下次执行next()时,从当前位置继续执行。

    yield关键字有两点作用:
    保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
    将 yield 关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用 

     验证

    1. def Fibonacci(all_nums):
    2. a, b = 0, 1
    3. current_num = 0
    4. print("----1----")
    5. while current_num < all_nums:
    6. print("----2----")
    7. yield a # 如果一个函数中有yield语句,那么这个就不再是函数了,而是一个生成器的模板
    8. print("----3----")
    9. a, b = b, a+b
    10. print("----4----")
    11. current_num += 1
    12. print("----5----")
    13. return "done"
    14. # 如果在调用Fibonacci的时候,发现这个函数中有yield,那么此时不再是调用函数,而是创建了一个生成器对象
    15. fib = Fibonacci(5)
    16. ret = next(fib)
    17. print("----6----")
    18. print(ret)
    19. ret = next(fib)
    20. print("----7----")
    21. print(ret)
    22. ret = next(fib)
    23. print("----9----")
    24. print(ret)

    生成器的应用

    读取大文件

    假如你读取大文件这样写,通常这都是没啥问题的。但如果这个文件非常非常大,那么将会得到内存溢出的报错。

    1. def csv_reader(file_name):
    2. file = open(file_name)
    3. result = file.read().split("\n")
    4. return result

    可以用生成器这样写

    由于这个版本的 csv_reader() 是个生成器,因此你可以通过遍历,加载一行、处理一行,从而避免了内存溢出的问题。

    1. def csv_reader(file_name):
    2. for row in open(file_name, "r"):
    3. yield row

    无限序列

    由于生成器一次只生成一个值,因此它可用于表示无限数据。

    1. def all_even():
    2. n = 0
    3. while True:
    4. yield n
    5. n += 2
    6. even = all_even()
    7. for i in even:
    8. print(i)

    优化内存

    1. def gen():
    2. for x in range(10000):
    3. yield x
    4. # 生成器
    5. my_gen = gen()
    6. # 列表
    7. my_list = [x for x in range(10000)]

    比较他们的大小

    1. >>> import sys
    2. >>> sys.getsizeof(my_list)
    3. 87616
    4. >>> sys.getsizeof(my_gen)
    5. 112

     生成器组合

    有时候你需要把两个生成器组合成一个新的生成器,比如:

    1. gen_1 = (i for i in range(0,3))
    2. gen_2 = (i for i in range(6,9))
    3. def new_gen():
    4. for x in gen_1:
    5. yield x
    6. for y in gen_2:
    7. yield y
    8. for x in new_gen():
    9. print(x)
    10. # 输出:
    11. # 0
    12. # 1
    13. # 2
    14. # 6
    15. # 7
    16. # 8

    这种组合迭代的形式不太方便,因此 Python 3.3 引入新语法 yield from 后,可以改成这样:

    1. def new_gen():
    2. yield from gen_1
    3. yield from gen_2

    生成器进阶语法

    send()

    我们除了可以使用 next() 函数来唤醒生成器继续执行外,还可以使用 send() 函数来唤醒执行。使用 send() 函数的一个好处是可以在唤醒的同时向断点处传入一个附加数据。

    1. def gen():
    2. count = 0
    3. while True:
    4. count += (yield count)
    1. >>> g = gen()
    2. >>> g.send(None)
    3. 0
    4. >>> g.send(1)
    5. 1
    6. >>> g.send(2)
    7. 3
    8. >>> g.send(5)
    9. 8

    throw()

    .throw() 允许用生成器抛出异常

    1. def my_gen():
    2. count = 0
    3. while True:
    4. yield count
    5. count += 1
    6. gen = my_gen()
    7. for i in gen:
    8. print(i)
    9. if i == 3:
    10. gen.throw(ValueError('The number is 3...'))
    11. # 输出:
    12. # 0
    13. # 1
    14. # 2
    15. # 3
    16. # ValueError: The number is 3...

    close()

    .close() 可以停止生成器

    1. def my_gen():
    2. count = 0
    3. while True:
    4. yield count
    5. count += 1
    6. gen = my_gen()
    7. for i in gen:
    8. print(i)
    9. if i == 3:
    10. gen.close()

    结论

    以上就是生成器的大致介绍了。它可以暂停控制流,并在你需要的时候随时回到控制流,从上一次暂停的位置继续执行。
    生成器有助于你处理大型数据流或者表达无限序列,是生成迭代器的有用工具。

  • 相关阅读:
    Unity笔记(3):制作[2D]角色骨骼与动画
    给手机上液冷?谈谈华为Mate 60系列手机专属黑科技—— “微泵液冷”手机壳
    LA@二次型分类@正定二次型@主子式
    视图、存储过程、触发器
    赞奇科技参与华为云828 B2B企业节,云工作站入选精选产品解决方案
    成考报名时间
    私有化轻量级持续集成部署方案--03-部署web服务(上)
    【C++编程语言】之 加号 左移 递增 赋值 关系 函数调用 的 运算符重载
    vue的双向绑定Object.definedProperty(obj,key,{set,get})
    pacemaker常用命令
  • 原文地址:https://blog.csdn.net/csdncjh/article/details/127252119