念念不忘,必有回响!繁华似锦觅安宁,淡云流水度此生--------潇洒若梦&&浮生执铭
潇洒浮生
因为你 我愿意热爱整个世界

生成器

生成器

生成器仅仅保存了一套生成数值或者对象的算法,并且没有让这个算法现在就开始执行,而是我什么时候调它,它什么时候开始计算一个新的值,并给你返回。

为何要用生成器

存储海量的数据会占用内存资源,如果我们可以根据算法推算后面的数据,什么时候需要的时候就去生成,这样将极大地减少内存占用。

创建生成器

1. 列表生成式的[]改成()

L = [x * x for x in range(10)]
print(L)

G = (x * x for x in range(10))
print(G)
print(next(G)

执行结果

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x02739DB0>
0

next是生成器能迭代的关键,next(G)等价于G.__next__(),调用他就生成一个新的对象并返回。

2. yield

在函数里面有yield关键字,函数就变成了一个生成器。当调用next()函数时,就相当于生成下一个对象(统称),这一次next开始的地方是接着上一次next停止的地方执行的,即yield之后继续执行,到yield处返回生成的对象。

例子

def fun():
    print('run fun')
    while True:
        rtn = yield 6
        print('rtn:',rtn)
g = fun()
print(g)
print(next(g))
print('-------')
print(next(g))
print('------------')
print(next(g))

执行结果

<generator object fun at 0x0278CDB0>
run fun
6
-------
rtn: None
6
------------
rtn: None
6

分析

  1. 程序开始执行以后,因为fun函数中有yield关键字,所以先得到一个生成器对象g,由print(g)可以看出他是一个生成器对象

  2. 直到调用next方法,fun函数正式开始执行,先执行fun函数中的print方法,然后进入while循环(++生成器都有一个while True循环以此不断生成对象并返回++)

  3. 程序遇到yield关键字,把yield想象成return,return了一个6之后,程序停止,并没有执行赋值操作,此时next(g)语句执行完成,返回6,是执行print(next(g))的结果,

  4. 程序执行print,,输出---

  5. 又开始执行下面的print(next(g)),这个时候是从刚才那个next程序停止的地方开始执行,也就是要执行rtn的赋值操作,这时候要注意,这个时候赋值操作的右边是没有值的(因为刚才那个是return出去了,并没有给赋值操作的左边传参数),所以这个时候rtn赋值是None,所以接着下面的输出就是rtn:None,继续走while循环

  6. 又一次碰到yield,这个时候同样return 出6,然后程序停止,print函数输出的6就是这次return的返回值.

  7. 继续5-6

再看

def fun():
    print('run fun')
    while True:
        rtn = yield 6
        print('rtn:',rtn)
g = fun()
print(g)
print(next(g))
print('-------')
print(g.send(True))
print('------------')
print(g.send('赋值操作'))

执行结果

<generator object fun at 0x029AEAB0>
run fun
6
-------
rtn: True
6
------------
rtn: 赋值操作
6

这次的rtn为什么有值了呢?

send和next区别
    1. send和next()都是让生成器向下走一次
    2. send可以给上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器代码的时候不能使用send()

send()干了两件事情:

  1. 发送一个参数做赋值操作
  2. 函数内部包含执行next(),yield 6 返回
posted on 2020-01-04 00:19  潇洒浮生  阅读(110)  评论(0编辑  收藏  举报

levels of contents