关于生成器,主要有以下几个 关键点的内容

一、什么是generator ,为什么要有generator?

二、两种创建生成器方式

三、yield关键字

四、generator 两个调用方法 next() 和send()

一、什么是generator ,为什么要有generator?

generator 是一种方式 ,是一种借助于循环,然后不断产生值的一种机制。(我是能理解机制这种描述,想了个例子来说明这个例子感觉又不对。)

那么为什么需要generator呢?一、 当你需要获取大量值的时候,我们可以将值存在列表里面,然后循环,读出没一个值。这没毛病。

但是你知道数组这种数据结构,他是将所有的值都紧挨着放在一块的,

当我们将这很多值,都放在内存中,主存是需要申请很大一块空间,

进行存放的,而我们的操作系统还要执行其他的任务,也要用到主存。这样将会导致操作RAM大量被占用,其他任何执行不了,或者干脆,其他任务执行完了,把地方让出来给你,你再去执行。以上的描述大家能感觉出来效率是非常低的。

可是我们有的时候就是需要啊,需要获取这种大量数据。(什么情况下,其实我写了几个项目现在也没有用到过generator,不过知道python的协程就是用生成器实现的。)而生成器他通过循环,计算出的数据,也就是说每循环一次就产生一次数据。这样是不需要向上面一样大量占用内存空间的,至于你说你需要计算啊(对于cpu来你这点代码量,简直就是连9牛一毛都称不上,这大兄弟可是每秒钟,能计算几十亿次)。

二、两种生成器的创建方式

1 、(x for x in range) ,就是将列表推到值外边的列表换成了元组。

2、函数中包含yield 关键字

def f1(n):
    yield n
obj = f1(1)
print(obj)

返回值是这个东西 <generator object f1 at 0x0000000001F1FFC0>
是一个生成器对象

  

三 、 yield 关键字

我们知道一个函数包含一个yield关键字 ,返回的就是一个generator ,那么这个yield关字是怎么运作的,他都有那些特性

请看如下代码,这个就是一个生产这消费者模型

def consumer():
    r = 'ok'
    while True:
        n1 = yield r
        while not n1:
            print('如果走了这里,说明,下一次调用之前先将上一次的NONE给赋值了')
        print('consumer consume %s'%(n1))
        r = '我不想吃包子,我想吃pizza'
def producer(c):
    data =c.send(None)
    print(data ,'到底一次yield有没有返回值')
    n=0
    while n <5:
        n+=1
        print('生产者生产了%s'%n)
        data_2=c.send(n)
        print('消费者其实想的是%s'%(data_2))
obj =consumer()
producer(obj)

  

我建议,如果你看了我的博客,可以复制一下代码去执行一下。就能总结出来yield关键字有如下特性:

1、yiled 关键字类似于return ,就是函数执行到这里后,就不在向下执行,然后返还一个返回值。但是(一提但是就要仔细看啊)当 执行到yield 关键字时,整个函数一个运行状态是还保存在内存,当下次再调用这个生成器时,会从yield开始,在向下执行,

而不是从函数开头从新执行一遍。然后循环到了yield 在卡住,等待下次再调用

2、yield 可以被传值,不过必须要通过send()方法

四、generator 两个调用方法 next() 和send()

我们一直在强调,generator 是借助于循环,不断产生新的值,所以就能理解 ,一般一个生成器都应该是一个循环中被调用,产生一个新的值。

所以

def f1(n):
    while True:
        n +=1
        yield n
obj = f1(1)

for i in obj:
    print(i)

你可尝试一下,无限循环的感觉。

  

当然一般情况下,不会是无限循环 ,肯定是有一个终止条件的。

如下

def f1(n):
    while n<5:
        n +=1
        yield n
obj = f1(1)

j =0
while j<5:
    j+=1
    try:
        print(next(obj))
    except StopIteration as e:
        print('别调用了,最多能计算这么多')

当生成器已经计算结束后,你在去调用会报错的 ,如果是直接用for 调用是不会报错的。其实for 结构里面就类似上面的代码,只是当循环完generator后,抓去了对应的异常。结束循环。

  

最后则是send 方法 , 而send 方法,他有两个作用,第一个是可以调用这个generator计算,第二个就是给yield赋值,在将上面的代码赋值一下

def consumer():
    r = 'ok'
    while True:
        n1 = yield r
        while not n1:
            print('如果走了这里,说明,下一次调用之前先将上一次的NONE给赋值了')
        print('consumer consume %s'%(n1))
        r = '我不想吃包子,我想吃pizza'
def producer(c):
    data =c.send(None)
    print(data ,'到底一次yield有没有返回值')
    n=0
    while n <5:
        n+=1
        print('生产者生产了%s'%n)
        data_2=c.send(n)
        print('消费者其实想的是%s'%(data_2))
obj =consumer()
producer(obj)

  关于send 方法有一个特性,就是在第一次启动生成器的时候,要传一个None,或者先用next调用一下。原因是,当第一次走到yield的时候,yield 直接将会返回值返回,然后这次执行就停掉了,并没有发生赋值的操作,所以你传进来一个值,是没有效果的所以python的源码里面就做了处理。而第二次在在用send唤醒generaot ,send方法在传一个值,在将这个值传给yield 关键字。然后yield在赋值,然后整个函数再向下运行。

还有个小点,就是在函数调用,生成一个generatro对象时,函数是什么执行的,只有在被调用,或者被for循环时,才开始执行。

最新文章

  1. 今天不谈技术,说说一些常用的软件~By 逆天
  2. .Net中DataAdapter批量插入和更新数据总结
  3. 纯CSS实现JS效果研究
  4. 洛谷P1901 发射站
  5. 去掉SrollView、GrdiView、ListView、ViewPager等滑动到边缘的光晕效果
  6. SVN提交提示:working copy is not up-to-date解决方法
  7. java总结第四次//常用类
  8. Win32下 Qt与Lua交互使用(三):在Lua脚本中connect Qt 对象
  9. CoreJava_线程并发(堵塞队列):在某个目录下搜索含有某keyword的文件
  10. PHP Math
  11. C# 运算符 if
  12. Protel99se教程二:使用protel99se原理图绘制
  13. leetcode第15题--3Sum
  14. SEO—Meta标签优化
  15. tomcat中Servlet的工作机制
  16. 运行vue遇到的坑(续更
  17. 自学Linux Shell11.5-执行数字运算
  18. [转载]AngularJS视图
  19. virtualbox+vagrant学习-2(command cli)-4-vagrant global-status命令
  20. oracle数据库中将clob字段内容利用java提取出至文本文档中

热门文章

  1. command not found
  2. SQLMAP注入教程-11种常见SQLMAP使用方法详解
  3. 第十六节:语法总结(3)(C#6.0和C#7.0新语法)
  4. 微信获取企业token流程
  5. java核心36
  6. Java Queue之PriorityQueue
  7. 解决radio、select表单返回时,再次选择失效
  8. mysql 迁移
  9. notepad++最详情汇总
  10. LINUX常见性能监控工具总结