• Python学习基础笔记二十二——生成器


    一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

     

    生成器函数的特点:

    1)调用函数之后函数不执行,返回一个生成器;

    2)每次调用next方法的时候会取到一个值;

    3)直到取完最后一个,在执行next会报错。

    1. def generator():
    2. print(1)
    3. return 'a'
    4. ret = generator()
    5. print(ret)

    只要含有yield关键字的函数都是生成器函数。

    1)yield只能写在函数里;

    2)yield不能跟return共用;

    1. def generator():
    2. print(1)
    3. yield 'a'
    4. ret = generator()
    5. print(ret)

    结果:

    生成器函数:执行之后会得到一个生成器对象作为返回值。

    1. def generator():
    2. print(1)
    3. yield 'a'
    4. ret = generator()
    5. print(ret)
    6. print(ret.__next__())

    结果:

    再看:

    1. def generator():
    2. print(1)
    3. yield 'a'
    4. print(2)
    5. yield 'b'
    6. g = generator()
    7. print(g)
    8. ret = g.__next__()
    9. print(ret)
    10. ret = g.__next__()
    11. print(ret)

    结果:

    如果再加ret = g.__next__() print(ret)代码,就会发生溢出。会出现迭代器取不到的时候,有stopIteration的错误提示。

    我们可以看到函数内部的执行,是受外部控制的。通过yield和__next__两者来对函数进行控制。

    1. def generator():
    2. print(1)
    3. yield 'a'
    4. print(2)
    5. yield 'b'
    6. g = generator()
    7. for i in g:
    8. print(i)

    既然有__iter__和__next__,那么我们可以使用for循环来管理。

    那我们现在看例子:

    1. def hello():
    2. for i in range(2000000):
    3. yield 'hello %s' % i
    4. g = hello()
    5. for i in g:
    6. print(i)

    背后的原理是:这边生产一个,然后就给你一个打印,边生产边打印,这样就不会一下子在内存中产生大量的数据。不是一次性将所有的数据都生成出来,然后再提供给你。这样,就需要大量的内存空间。数据越存越多,越到后面,程序需要去找内存,非常麻烦。

    如果只想打印50个:

    1. def hello():
    2. for i in range(2000000):
    3. yield 'hello %s' % i
    4. g = hello()
    5. count = 0
    6. for i in g:
    7. count += 1
    8. print(i)
    9. if count > 50:
    10. break
    11. # print(g.__next__())
    12. for i in g:
    13. count += 1
    14. print(i)
    15. if count > 100:
    16. break

    这个应该有一个位置记录,迭代的过程中记录下一个位置。下一个for循环就从下一个位置开始获取值。

    1. l = [1, 2, 3, 4, 5]
    2. for i in l:
    3. print(i)
    4. if i == 2:
    5. break
    6. for i in l:
    7. print(i)

    这个例子里说for循环,是生成了一个迭代器。然后for循环结束之后,第二个for循环,迭代器又从头开始执行。

    看一个工厂生产衣服的例子:

    1. def produce():
    2. """生产衣服"""
    3. for i in range(2000000):
    4. yield "生产了第%s件衣服"%i
    5. product_g = produce()
    6. print(product_g.__next__()) #要一件衣服
    7. print(product_g.__next__()) #再要一件衣服
    8. print(product_g.__next__()) #再要一件衣服
    9. num = 0
    10. for i in product_g: #要一批衣服,比如5件
    11. print(i)
    12. num +=1
    13. if num == 5:
    14. break
    15. #到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
    16. #剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿

    一个函数可以监听文件的输入:

    1. def tail(filename):
    2. f = open(filename, encoding='utf-8')
    3. while True:
    4. line = f.readline()
    5. if line.strip():
    6. yield line.rstrip()
    7. g = tail('log')
    8. for i in g:
    9. if 'python' in i:
    10. print('hello', i)

    总结:

    从生成器中取值的几个方法:

    1)next

    2)for

    3)数据类型的强制转换:占用内存。

    1. # 处理文件,用户指定要查找的文件的内容,将文件中包含要查找的内容的每一行都输出到屏幕
    2. def check_file(fn, cont):
    3. with open(fn, 'r', encoding='utf-8') as f:
    4. for i in f:
    5. if cont in i:
    6. yield i
    7. filename = input('filename: ')
    8. content = input('content: ')
    9. g = check_file(filename, content)
    10. for i in g:
    11. print(i.strip())

  • 相关阅读:
    猿创征文|JAVA 实现《连连看》游戏
    计算机毕业设计成品java项目开发实例SSM+MySQL实现的家庭医生预约平台
    在 Vue 的 mounted 钩子函数中使用异步函数是否会有风险需要考虑
    【Agora UID 踩坑记录 && Java 数据类型】
    【GPU】Nvidia CUDA 编程高级教程——利用蒙特卡罗法求解近似值(MPI方法)
    vuex的概念及环境配置
    《数据结构、算法与应用C++语言描述》-栈的应用-开关盒布线问题
    FFmpeg命令行详解
    Linux C/C++ 多线程开发 - 基础介绍
    第六章第二节:图的遍历(广度优先遍历和深度优先遍历)和应用(最小生成树、最短路径、有向无环图的描述表达式、拓扑排序、关键路径)
  • 原文地址:https://blog.csdn.net/chang_chunhua/article/details/128177780