一、在讲解协程之前,先了解什么是Python迭代器
1)概念:迭代器是访问集合元素的一种方式,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前,不能后退。
2)特性----惰性求值:迭代器不要求你事先准备好整个迭代过程中所有的元素,仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者销毁。这个特点使其适用于遍历一些巨大或无限的集合。
3)可迭代对象:
序列:元组、列表、字符串
非序列:字典、文件
自定义类:实现了__iter__() 或 __getitem__() 方法的对象
如何判断对象是否可迭代:利用Iterable,True则表示该对象可以迭代,False表示不可以迭代。
4)创建迭代器对象
案例一:建立一个可以用来迭代的类,实现迭代器
# coding:utf-8
from collections import Iterable
from collections import Iterator
import time
# 如何判断一个对象是否可以迭代? 若是True,则证明可以迭代
# print(isinstance([11,22,33], Iterable))
"""目标:建立一个可以用来迭代的类,实现迭代器"""
class Classmate(object):
def __init__ (self):
self.names = list()
def add(self,name):
self.names.append(name)
def __iter__(self):
return ClassIterator(self)
class ClassIterator(object):
def __init__(self,obj):
self.obj = obj
self.current_num = 0
def __iter__(self):
pass
def __next__(self):
if self.current_num < len(self.obj.names):
ret = self.obj.names[self.current_num]
self.current_num+=1
return ret
else:
raise StopIteration
classmate = Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("老王")
for name in classmate:
print(name)
time.sleep(1)
运行结果:
张三
李四
老王
案例二:实现类的迭代的第二种方法,上述两个类合并
# coding:utf-8
from collections import Iterable
from collections import Iterator
import time
# 如何判断一个对象是否可以迭代? 若是True,则证明可以迭代
# print(isinstance([11,22,33], Iterable))
"""目标:建立一个可以用来迭代的类,实现迭代器"""
class Classmate(object):
def __init__ (self):
self.names = list()
self.current_num = 0
def add(self,name):
self.names.append(name)
def __iter__(self):
return self
def __next__(self):
if self.current_num < len(self.names):
ret = self.names[self.current_num]
self.current_num+=1
return ret
else:
raise StopIteration
classmate = Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("老王")
for name in classmate:
print(name)
time.sleep(1)
运行结果同上一个案例。
案例三:生成Fibonacci数列的两种方法
1)数列的形式:
a=0
b=1
num = 0
nums=list()
nums.append(a)
while num<10:
a,b = b,a+b
nums.append(a)
num+=1
for i in nums:
print(i)
运行结果:
0
1
1
2
3
5
8
13
21
34
55
2)使用迭代器实现
# coding:utf-8
# 使用迭代器方法构建 Fibonacci 数列
from collections import Iterable
from collections import Iterator
import time
"""目标:使用迭代器实现Fibonacci数列"""
class Fibonacci(object):
def __init__ (self,all_num):
self.all_num = all_num
self.current_num = 0
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
if self.current_num < self.all_num:
ret = self.a
self.a, self.b = self.b, self.a+self.b
self.current_num+=1
return ret
else:
raise StopIteration
fib = Fibonacci(10)
for num in fib:
print(num)
运行结果同上。
二、Python生成器 (yield/send)
案例一:使用生成器方法构建Fibonacci数列
# coding:utf-8
# 使用生成器方法构建 Fibonacci数列
def create_num(all_num):
print("----1----")
a, b = 0, 1
current_num = 0
while current_num < all_num:
print("----2----")
yield a
print("----3----")
a, b = b, a+b
current_num += 1
print("----4----")
# 通过迭代器的 next() 查看生成器中的运行顺序,即 yield是暂停的一个功能
obj = create_num(10)
ret = next(obj)
print(ret)
ret = next(obj)
print(ret)
运行结果:
----1----
----2----
0
----3----
----4----
----2----
1
案例二:捕获异常(try)
# coding:utf-8
# 如何通过捕获异常的情况来判断迭代的结束
def create_num(all_num):
a, b = 0, 1
current_num = 0
while current_num < all_num:
yield a
a, b = b, a+b
current_num += 1
return "ok----"
# 通过迭代器的 next() 查看生成器中的运行顺序,即 yield是暂停的一个功能
# 使用try捕获异常
obj = create_num(10)
while True:
try:
ret = next(obj)
print(ret)
except Exception as ret: # 判断结束
print(ret.value)
break
案例三:使用send启动生成器
# coding:utf-8
# 使用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(10)
ret = next(obj)
print(ret)
ret = obj.send("hahaha")
print(ret)
运行结果:
0
----ret---- hahaha
1
三、使用yield实现多任务
# coding:utf-8
# 使用yield完成多任务
import time
def task_1():
while True:
print("----1----")
time.sleep(0.2)
yield
def task_2():
while True:
print("----2----")
time.sleep(0.2)
yield
def main():
t1 = task_1()
t2 = task_2()
while True:
next(t1)
next(t2)
if __name__ == "__main__":
main()
运行结果:
----1----
----2----
----1----
----2----
----1----
----2----
----1----
----2----
----1----
----2----
四、使用greenlet实现多任务
# coding:utf-8
# 使用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()
运行结果:
----A----
----B----
----A----
----B----
五、实现gevent实现多任务:
# coding:utf-8
# 使用gevent实现多任务
import gevent
import time
def f1(n):
for i in range(n):
print(gevent.getcurrent(),i)
# time.sleep(0.5)
gevent.sleep(0.5)
def f2(n):
for i in range(n):
print(gevent.getcurrent(),i)
# time.sleep(0.5)
gevent.sleep(0.5)
def f3(n):
for i in range(n):
print(gevent.getcurrent(),i)
# time.sleep(0.5)
gevent.sleep(0.5)
print("----1----")
g1 = gevent.spawn(f1,5)
g2 = gevent.spawn(f2,5)
g3 = gevent.spawn(f3,5)
g1.join()
g2.join()
g3.join()
运行结果:
----1----
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 0
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 0
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 0
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 1
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 1
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 1
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 2
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 2
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 2
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 3
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 3
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 3
<Greenlet "Greenlet-0" at 0x2aa5c0c0748: f1(5)> 4
<Greenlet "Greenlet-1" at 0x2aa5c0c0a48: f2(5)> 4
<Greenlet "Greenlet-2" at 0x2aa5c0c0b48: f3(5)> 4
六、使用gevent实现多任务的另外一种方法
# coding:utf-8
# 使用gevent实现多任务 (解决 time.sleep() 的问题)
import gevent
import time
from gevent import monkey
monkey.patch_all()
def f1(n):
for i in range(n):
print(gevent.getcurrent(),i)
time.sleep(0.5)
def f2(n):
for i in range(n):
print(gevent.getcurrent(),i)
time.sleep(0.5)
def f3(n):
for i in range(n):
print(gevent.getcurrent(),i)
time.sleep(0.5)
gevent.joinall([
gevent.spawn(f1,5),
gevent.spawn(f2,5),
gevent.spawn(f3,5)
])
运行结果同上。