6.Python生成器-next和send方法

本文详细介绍了Python生成器的概念,强调了next方法和send方法的使用。next方法用于启动或继续生成器的执行,而send方法不仅有相同功能,还能传递参数给生成器。send(None)等同于next(),但直接使用send而不传None会导致错误。send方法允许在生成器执行过程中改变yield表达式的值,增加了交互性。最后,展示了如何使用for循环便捷地遍历生成器输出。

之前一直感觉对生成器的理解不够,想再专门写一篇深入理解一下生成器:

1.生成器简介:

python中,含有yield关键字的对象就是一个生成器,每次调用next方法时会执行到yield后面的语句,然后返回yield后面代码块的执行结果,并挂起。

next方法
def foo():
    a = yield 1  # bar_a是语句块(yield 1)的返回值,默认为None
    b = yield a
    yield "最后一个值,再迭代就要报StopIteration了"


f = foo()  # 创建生成器,此时没有执行foo()里的任何语句
print(next(f))  # 从foo()里进入,一直执行到(yield 1)处,此时变量a还没有创建,直接返回yield后面的代码块
print(next(f))  # 先将语句块(yield 1)的返回值赋值个a,此时a的值是None。
# 然后执行到语句块(yield a),b也还没有被创建
print(next(f))


执行结果:
1
None
最后一个值,再迭代就要报StopIteration了

第一个next调用,相当于启动生成器,会从生成器函数的第一行代码开始执行,直到第一次执行完yield语句后,跳出生成器函数,并将yield关键字后面的内容返回给调用者;
第二个next调用从yield语句的下一句语句开始执行,直到遇到yield或者元素迭代完毕。
而且我们可以看到a和b是语句yield 1和yield a的返回值,注意:不是生成器的返回值。

这里有个比较绕的地方,我们用a = yield 1做分析:

1是生成器的返回值。因为生成器返回yield后面的代码块

a是语句yield 1的返回值,这就好比我们写

       a = print('my lover')
        print('a的值是:', a)
输出:

    my lover
    a的值是: None
send方法
def foo():
    a = yield 1
    b = yield a
    yield "最后一个值,再迭代就要报StopIteration了"


f = foo()
print(f.send(None))
print(f.send("my lover"))
print(next(f))、

输出结果:
1
my lover
最后一个值,再迭代就要报StopIteration了

这里f.send(None)是初始化生成器,和next(f)的效果一模一样。但是不推荐这么写,因为不规范。如果直接写send不输入None或者不执行Next,就会报错;
注意输出的第二行是字符串my lover,而不是None。这是因为send函数带有一个参数,这个参数会覆盖yield 1语句的返回值,也就是不管yeild后面进行了什么运算都会被覆盖,也就是a的值现在不是None了。

a = yield 1这句话是从右往左执行的。当第一次send(None)时,启动生成器,从生成器函数的第一行代码开始执行,直到第一次执行完yield后,跳出生成器函数并返回结果1。这个过程中,a一直没有定义。
运行到send('my love’r)时,进入生成器函数,此时,将yield a看做一个整体,赋值给它并且传回。此时即相当于把"my lover赋值给b,即send和next相比,只是开始多了一次赋值的动作,其他运行流程是相同的

实际上next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的。

第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有Python yield语句来接收这个值
send方法和next方法唯一的区别是在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互。

举例:

def test():
    i=0
    while i<5:
        temp=yield i*2
        print(temp)
        i=i+1

a=test()     # 生成器对象 ,里面都是存储 i*i的值

print("next start")
print(next(a))   #取第一个i*i值

print("__next__ start")
print(a.__next__())  # 换种方法 取第二个 i*i 值

print("send start")
print(a.send("hahha"))  # 这个send 方法 可以传入参数, 并且 yield 进行接受,说明yield 既可以存储 i*i的值 ,也可以接受参数并赋值给temp
print(a.send("heihei"))

运行结果:

next start
0
__next__ start
None
2
send start
hahha
4
heihei
6

总结: 目前为止 我们可以取生成器的方法有三种 1.next(),2.( next) 3. send(arg) 这个不但可以取值,也可以传递参数

大家感觉不停的用next()方法进行取值,非常的麻烦,大家还记得吗,

使用for循环输出生成器结果:

生成器也是迭代器, 迭代器既可以用next()取值,也可以用for循环(可迭代特性)

def test():
    i=0
    while i<5:
        temp=yield i*2
        print(temp)
        i=i+1

a=test()     # 生成器对象 ,里面都是存储 i*i的值

for i in a:
    print(i)

运行结果:

0
None
2
None
4
None
6
None
8
None
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值