Discuss / Python / 看的晕头转向,在网上查了一下关于 yield 表达式的介绍,将本节的例子稍作修改,个人理解如下:

看的晕头转向,在网上查了一下关于 yield 表达式的介绍,将本节的例子稍作修改,个人理解如下:

Topic source

一雷叔一

#1 Created at ... [Delete] [Delete and Lock User]

看的晕头转向,在网上查了一下关于 yield 表达式的介绍,将本节的例子稍作修改,个人理解如下:

某个函数包含了yield,这意味着这个函数已经是一个Generator,yield是一个表达式(Expression),通过send(msg)语句让它执行, 并直到下一个yield表达式处,再次调用会接着上次的位置继续执行; send(msg)传递值msg给yield表达式并返回下一个yield表达式的参数,当第一次使用send(None)调用时,yield不执行,此时直接返回等待下一次send()调用; 注意:第一次调用时,需使用send(None)语句,不能使用send发送一个非None的值,否则会出错的,因为没有yield语句来接收这个值。 如:

def consumer(): r = '' while True:

    #因为此处为无限循环,所以从send(None)开始,每次yield返回值后都会停留在此。
    #这里的(yield r)为一个表达式,值为send(msg)传递的msg,返回的为r的值,第一次send(None)时,yield直接返回r值后,便停止在这里:
    n1 = yield r

    #此处的判断条件其实一次都没有True过,也就是里面的代码没有被执行过:
    # 因为第一次调用send(None)时,在yield处直接返回等待下一次的send()调用了,返回的值为r=’‘,其后n1的值分别为1~5:
    if not n1:
        print('被执行过!')
        return

    print('[CONSUMER] Consuming %s...' % n1)
    #此处为了便于分析yield每次的返回值,让r的值每次都不同
    r = ' 200 OK ' + r

def produce(c): bb = c.send(None) # bb = '' n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s' % n)

    #此处c.send(n)在传递完n的值后,每次都返回(yield r)的值,也就是r的值
    r1 = c.send(n)
    print('[PRODUCER] Consumer return: %s' % r1)
c.close()

c = consumer() produce(c)

多谢!

Eliefly

#3 Created at ... [Delete] [Delete and Lock User]

感谢!更清楚了。

梦_轩昂

#4 Created at ... [Delete] [Delete and Lock User]

如果你把consumer中的r初始化为'xxx',然后你再执行send(None),这个时候 x = c.send(None),你会发现x = 'xxx',这说明send(None)也是如执行next(c)是一样的,相当于传了一个None的参数,我是这么理解的。

yield真是有点晕

看了这个解释有点清楚了

Drak_C

#7 Created at ... [Delete] [Delete and Lock User]

十分感谢

逝去的9211

#8 Created at ... [Delete] [Delete and Lock User]

很遗憾的告诉你,你对yield的用法基本理解错了。 具体yield的用法可以看具体的官方文档(文档是最准的)。


以下讲的next()都是object的前后双下划线next方法


我简单讲一下 yield <expression> 解释器在遇到这个语句时,先计算expression,然后将结果返回给上一个调用者。而在第二次调用next()时,会从yield的下个语句开始执行。而不是你所理解的。

而讲到send()和next()的区别:

1 def consumer(): 2 r = 'here' 3 for i in xrange(3): 4 yield r 5 r = '200 OK'+ str(i)

6

7 c = consumer() 8 n1 = c.next () 9 n2 = c.next () 10 n3 = c.next ()

对于普通的生成器,第一个next 调用,相当于启动生成器,会从生成器的第一行代码开始执行,直到第一次执行完yield语句(第4行),然后跳出生成器函数。 然后第二个next 调用,从yield语句的下一句语句执行(第5行),然后重新运行到yield语句,执行后跳出,后面的以此类推。

1 def consumer(): 2 r = 'here' 3 while True: 4 n1 = yield r 5 if not n1: 6 return 7 print('[CONSUMER] Consuming %s...' % n1) 8 r = '200 OK'+str(n1) 9 10 def produce(c): 11 aa = c.send(None) 12 n = 0 13 while n < 5: 14 n = n + 1 15 print('[PRODUCER] Producing %s...' % n) 16 r1 = c.send(n) 17 print('[PRODUCER] Consumer return: %s' % r1) 18 c.close() 19 20 c = consumer() 21 produce(c)

send(msg)和next ()在一定程度上是类似的,区别是send()可以传递yield表达式的值进去,而next ()不能,只能传递None进去。我们可以看做next ()和send(None)是一致的 注意:第一次调用时,使用next ()或send(None),不能使用send发送一个非None的值,否则会报错,因为没有python yield语句来接收这个值。 第一次执行send(None)(11行),启动生成器,第一行代码执行到yield后,跳出生成器函数,此时,n1一直没有定义。 下面运行到c.send(1),进入生成器函数,从第4行开始执行,先把1赋值给n1,但是并不执行yield语句部分。 下面继续从yield的下一语句继续执行,然后重新运行到yield语句,执行后,跳出生成器。

综上,send和next 相比,多了一次赋值的动作,其他的流程是相同的。

你前面说的 “而在第二次调用next()时,会从yield的下个语句开始执行。而不是你所理解的。”从yield下个语句执行,这个下个语句是不是 赋值操作 “ n1 = yield r”。也就是说 n1 = yield r是两个操作? 因为之前说从下个语句开始执行,但是代码那块说的是先赋值。 用python debug一步一步操作,下一次send(value)时候,直接运行下一行了。但是之前的赋值n1已经操作完了。

GirlBeautiful

#10 Created at ... [Delete] [Delete and Lock User]

n1 = yield r

next()执行yield r返回r作为generator函数的返回值

第二次next()
从n1 = yield r的下一条语句执行。

如果是send(1)
首先把1 赋予n1,才从n1 = yield r的下一条语句执行。

n1 = yield r是两个操作
第一个操作是执行yield r,执行完后没有返回值,但是把r 作为generator函数的执行结果返回。(这里不好理解:yield r执行了,但是没有返回值作为执行结果。同时r又可以作为generator函数的执行结果返回给调用generator函数的表达式。需要认真思考,方能理解。理解万岁!)
第二个操作是下次send(n)调用generator函数时首先给n1赋值。

  • 1

Reply