生成器
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()
运行后图片自动下载在当前的目录之中。