Python入门——yield 生成器用法解析

版权声明:欢迎转载,但是请标明文章作者和出处。 https://blog.csdn.net/handsomehuo/article/details/91491305

yield有点类似于return,也是返回数值的作用,但是在使用过程中有很多不一样的特点。

首先说一下yield的使用背景,是为了节省内存,当我们使用传统方法时,比如生成含有十万个数值的列表,很可能会把内存占满,但是yield方法不是全部生成,而是一个一个按照指令生成,不会事先全部生成,所以会省内存。

记住了这个背景,再来理解yield的特性就会好懂了。

  • 定义一个函数,如果其中有yield,那么在函数初始化过程中,只是生成了generator,并不直接执行函数。
  • 如果想往下执行,那么使用__next__()方法,使用后会执行代码块中内容。
  • __next__()方法会执行到下一个yield处停止,并返回相应数值。
  • 如果继续往下没有找到下一个yield,编辑器会报错stopIteration。

来看下代码

def function():
    print('first yield')
    yield 1
    print('second yield')
    yield 2
    print('third yield')
    yield 3
    print('forth yield')

func1 = function()
print('生成器初始化', func1, '\n--------1执行完毕')
print('生成器到第一个yield停止', func1.__next__(), '\n--------2执行完毕')
print('生成器到第二个yield停止', func1.__next__(), '\n--------3执行完毕')
print('生成器到第三个yield停止', func1.__next__(),'\n---------4执行完毕')
print('生成器找不到到第四个yield报错', func1.__next__(), '\n--------5执行完毕')

输出:

生成器初始化 <generator object function at 0x1041179a8> 
--------1执行完毕 #第一个Print 没有返回值
first yield
生成器到第一个yield停止 1 
--------2执行完毕 #第二个print 输出了字符串,返回了1
second yield
生成器到第二个yield停止 2 
--------3执行完毕 #第三个print 继续往下执行,输出了字符串,返回了2
third yield
生成器到第三个yield停止 3 
---------4执行完毕 #第4个print ,继续往下执行,输出了字符串,返回了3
forth yield  #第5个print 继续往下执行,但是没找到yield,因此报错,'-------5执行完毕'没有执行输出
Traceback (most recent call last):
  File "/Volumes/Others/DM/oldboy/test.py", line 39, in <module>
    print('生成器找不到到第四个yield报错', func1.__next__(), '\n--------5执行完毕')
StopIteration
  • send(argv)比__next__()的作用要多一个,既给出指令往下执行next,还要给上一个yield位置传值argv,_next_()相当于send(None)。

来看下示例:

def function():
    print('first yield')
    a = yield 1
    print(a)
    print('second yield')
    b = yield 2
    print(b)
    print('third yield')
    c = yield 3
    print(c)
    print('forth yield')

func1 = function()
print(func1.__next__(), '---------1执行完毕' ) #也可以使用func1.send(None)
print(func1.send('py'),'------2执行完毕')
print(func1.send('th'),'------3执行完毕')
print(func1.send('on'),'------4执行完毕')

输出:

first yield
1 ---------1执行完毕 #第一个print输出 返回了1
py
second yield
2 ------2执行完毕 #第二个print输出 返回了a的赋值'py',返回了2
th
third yield
3 ------3执行完毕 #第三个print输出 返回了b的赋值'th',返回了3
on
forth yield #第4个print输出 返回了c的赋值'on' 但是没找到下一个yield,后面就报错了
Traceback (most recent call last):
  File "/Volumes/Others/DM/oldboy/test.py", line 41, in <module>
    print(func1.send('on'),'------4执行完毕')
StopIteration

Process finished with exit code 1

感觉还是很乱,对吧,其实重点理解一下这个赋值语句:

a = yield 1

#这一个赋值语句,分了2步执行,第一步返回值1,这是上一个yield的执行结果,第二步,根据send函数传过来的值赋给了a,执行到下一个yield结束,这两步没有直接关系。

执行顺序如图:

最后就很容易理解协程的概念了(人为控制程序和代码的跳转,以达到快速处理任务不等待的目的),使用yield处理经典的消费者和生产者模型,代码来自廖雪峰大神的python教程。

def consumer():
    r = ''
    while True:
        n = yield r #把r的值传给produce()
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None) #启动generator,此时r为空,返回了一个空值
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n) 
#跳到了consumer(),把n给到上一个yield位置并往下执行,这里的r是接收consumer返回的yield r。
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

c = consumer() #生成了一个generator
produce(c) #把generator当做参数传入produce函数

猜你喜欢

转载自blog.csdn.net/handsomehuo/article/details/91491305