生成器

本文介绍了Python生成器的创建方式,包括通过函数定义和使用`yield`关键字。详细讲解了`yield`的作用,如何使用`send()`唤醒并传递数据。接着探讨了生成器在并发执行(协程)中的应用,通过greenlet和gevent库实现协程的案例分析,展示了生成器如何提升并发执行效率。
摘要由CSDN通过智能技术生成

生成器

1.创建生成器的第一种方式

ipython中:

In [1]: nums = (x*2 for x in range(10))

In [2]: nums
Out[2]: <generator object <genexpr> at 0x7fb2a6137fc0>

In [3]: for num in nums:
   ...:     print(num)
   ...:
0
2
4
6
8
10
12
14
16
18

2.创建生成器的第二种方式(定义一个函数,让这个函数变成生成器)

生成斐波那契数列:1 1 2 3 5 8 13…

def fib(num):
    a,b,count = 0,1,1
    while count <= num:
        print(b)
        a,b = b,a+b
        count +=1
fib(1000)

3.函数中的yeild

如果在调用函数的时候,发现这个函数中有yeild
那么此时,也就不是调用函数了,而是创建了一个生成器对象

def creat_num(all_num):
    print('~~~~~~~~~~~1~~~~~~~~~~~~~~~~~')
    a,b=0,1
    current_num  = 0
    while current_num < all_num:
        print('~~~~~~~~~2~~~~~~~~~~~~~~~~~')
        yield a # 相当于暂停了程序
        #print(a)
        print('~~~~~~~~~~~~~~3~~~~~~~~~~~~')
        a,b = b,b+a
        current_num += 1
        print('~~~~~~~~~~~4~~~~~~~~~~~~~~~~')

obj = creat_num(5)        #此时.我们发现程序会报错(告诉我们,生成器里面没有东西了)

while True:        	  #写成死循环,取出所有值
    try:
        ret = next(obj)
        print('obj:',ret)
    except Exception as ret:
        print(ret.value)
        break

obj = creat_num(5)        #一个一个的取值
print(obj)
ret = next(obj)
print(ret)
ret1 = next(obj)
print(ret1)
ret2 = next(obj)
print(ret2)
ret3 = next(obj)
print(ret3)
ret4 = next(obj)
print(ret4)
ret5 = next(obj)
print(ret5)

for num in obj:   	  #for循环取值
    print(num)

两个生成器对象之前并没有任何关系

obj2 = creat_num(100)
print(obj2)
ret4 = next(obj2)
print(ret4)

4.使用send唤醒程序

使用send()函数来唤醒程序执行,使用send()函数的好处是
可以在唤醒的同时向断点中传入一个附加的数据

def create_num(all_num):
    a,b = 0,1
    current_num = 0
    while current_num < all_num:
        ret = yield a
        print('>>>>>>>>ret>>>>>>>',ret)
        a,b = b,a+b
        current_num += 1


obj = create_num(100)
# red = next(obj)
# print(red)
red = obj.send(None)
print(red)

next和send得到的都是yield后面的值
不同的是send传递值而next不传递值

注意:
不能把send放在第一个,因为第一次执行程序是从开始执行,并没有值来接收send;
如果你非要把send放在第一个,那么传递的值应该是None。

5.生成器的应用

例一:

def task_01():
    while True:
        print('----1----')
        time.sleep(0.1)
        yield

def task_02():
    while True:
        print('-----2-----')
        time.sleep(0.1)
        yield

def main():
    t1 = task_01()
    t2 = task_02()
    while True:
        next(t1)
        next(t2)
        
main()

结果图:

在这里插入图片描述

结果分析:
调用主函数(main())中True死循环,所以在不断的调用t1和t2。

例二:

import time

def consumer(name):
    print('%s 准备学习' % (name))
    while True:
        lesson = yield
        print('开始[%s]了,[%s]老师来了' % (lesson, name))

def producer():
    c1 = consumer('A')
    c2 = consumer('B')
    c1.__next__()       #上一个函数中内部的next
    c2.__next__()
    print('同学们开始上课了')
    for i in range(10):
        time.sleep(1)
        print('到了两个同学')
        c1.send(i)
        c2.send(i)

producer()

结果图:

在这里插入图片描述

结果分析:
调用主函数produce()后,内部两次调用consumer()函数。

6.通过greenlet完成协程

通过网络以及下方的命令

/usr/local/python3/bin/pip3 install greenlet

下载greenlet第三方模块库(超级用户)。

在这里插入图片描述

举例:

from greenlet import greenlet
import time


def test1():
    while True:
        print('----A----')
        gr2.switch()
        time.sleep(0.5)


def test2():
    while True:
        print('----B----')
        gr1.switch()
        time.sleep(0.5)

gr1 = greenlet(test1)
gr2 = greenlet(test2)

gr1.switch()

结果图:

在这里插入图片描述

结果分析:
按顺序依次执行函数。

7.通过gvent完成协程

通过网络和下方命令

/usr/local/python3/bin/pip3 install gevent

下载gevent模块库(超级用户)。

举例:

import gevent

def f1(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        gevent.sleep(0.5)

def f2(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        gevent.sleep(0.5)

def f3(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        gevent.sleep(0.5)

g1 = gevent.spawn(f1,5)
g2 = gevent.spawn(f2,5)
g3 = gevent.spawn(f3,5)

g1.join()
g2.join()
g3.join()

结果图:

在这里插入图片描述

结果分析:
此时三个函数都有延迟0.5的设定,结果中三个函数依次按顺序进行。

测试:
我们将f3(n)中的gevent.sleep(0.5)用#注释掉。

结果图:

在这里插入图片描述

结果分析:
此时,f3(n)函数中无延迟。我们发现结果图中,f1和f2先进行,进行f3时发现f3无延迟,所以随后先将f3进行完成。完成f3全部内容后,f1和f2在进行系统资源的交叉占用。

举例——下载图片:

import urllib.request
import gevent
from gevent import monkey

def downloder(img_name,img_url):
    req = urllib.request.urlopen(img_url)
    img_content = req.read()
    with open(img_name,'wb') as f:
        f.write(img_content)

def main():
    gevent.joinall([
        gevent.spawn(downloder,'1.jpg','https://ww2.sinaimg.cn/thumb150/549761d5gy1fxumavwz7jj20v817dk0r.jpg'),
        gevent.spawn(downloder,'2.jpg','https://ww2.sinaimg.cn/thumb150/549761d5gy1fxumavwz7jj20v817dk0r.jpg')
    ])

main()

运行后图片自动下载在当前的目录之中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值