首发地址
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有元素被访问完结束。迭代器只能往前不会后退。
In [1]: from collections.abc import Iterable In [2]: isinstance("abc",Iterable) Out[2]: True In [3]: isinstance([1,2,3],Iterable) Out[3]: True In [4]: isinstance(123,Iterable) Out[4]: False
返回为True即为可迭代
class Classmate(object): def __init__(self): self.names = list() self.current_num = 0 def add(self,name): self.names.append(name) def __iter__(self): #如果想要一个对象 可以迭代,即可以使用for,那么必须实现__iter__方法 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("小1") classmate.add("小2") classmate.add("小3") for i in classmate: print(i)
class Fibonacci(object): def __init__(self,max_num): self.max_num = max_num self.current_num = 0 self.front = 0 self.after = 1 def __iter__(self): return self def __next__(self): if self.current_num < self.max_num: ret = self.front self.front, self.after = self.after, (self.front + self.after) self.current_num += 1 return ret else: raise StopIteration fibo = Fibonacci(20) for num in fibo: print(num)
并不是只有for循环能够接受可迭代对象,除for循环外,list、tuple等也能接受。
a = (11,22,33) list(a) #此处list(a)不是单纯的类型转换,而是首先创建一个空列表,然后调用next方法,一个一个的往列表中添加。
生成器是一种特殊的迭代器
In [1]: nums = [x*2 for x in range(5)] In [2]: nums Out[2]: [0, 2, 4, 6, 8] In [3]: nums = (x*2 for x in range(5)) In [4]: nums Out[4]: <generator object <genexpr> at 0x000001DC00D7AF20>
如果一个函数中,存在yield语句,那么它就不是一个函数而是一个生成器
def create_num(all_num): a, b, current_num = 0, 1, 0 while current_num < all_num: yield a a, b = b, a + b current_num += 1 generator = create_num(100) #generator就是一个生成器对象 for num in generator: print(num)
def create_num(all_num): a, b, current_num = 0, 1, 0 while current_num < all_num: yield a a, b = b, a + b current_num += 1 return "ok ..." generator = create_num(100) for i in range(102): try: print(next(generator)) except StopIteration as e: print(e.value) break
send与next的区别,send可以向生成器中传参
def create_num(all_num): a, b, current_num = 0, 1, 0 while current_num < all_num: ret = yield a print(ret) a, b = b, a + b current_num += 1 return "ok ..." generator = create_num(100) print(next(generator)) print(generator.send("传参"))
第一次启动生成器,如果使用send,不能传值。第一次建议使用next,非要使用send,可以传入None这个空值。
import time def task_1(): while True: print("---1---") time.sleep(0.1) yield def task_2(): while True: print("---2---") time.sleep(0.1) yield def main(): t1 = task_1() t2 = task_2() while True: next(t1) next(t2) if __name__ == "__main__": main()
安装greenlet
pip install greenlet
greenlet
import time from greenlet import greenlet 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()
greenlet已经实现了协程,但是还需要人工切换。gevent可以自动切换
安装gevent
pip install gevent
简单实现
import gevent def f(n): for i in range(n): print(gevent.getcurrent(),i) #只有使用gevent.sleep才会切换 gevent.sleep(1) g1 = gevent.spawn(f,5) g2 = gevent.spawn(f,5) g3 = gevent.spawn(f,5) g1.join() g2.join() g3.join()
monkey.patch_all()
import gevent from gevent import monkey import time monkey.patch_all() #monkey.patch_all()给程序打补丁,程序当遇到耗时的代码,会换为gevent中自己实现的模块 def f(n): for i in range(n): print(gevent.getcurrent(),i) #只有使用gevent.sleep才会切换 time.sleep(1) g1 = gevent.spawn(f,5) g2 = gevent.spawn(f,5) g3 = gevent.spawn(f,5) g1.join() g2.join() g3.join()
简洁写法
import gevent from gevent import monkey import time monkey.patch_all() #monkey.patch_all()给程序打补丁,程序当遇到耗时的代码,会换为gevent中自己实现的模块 def f(n): for i in range(n): print(gevent.getcurrent(),i) #只有使用gevent.sleep才会切换 time.sleep(1) gevent.joinall([gevent.spawn(f,5),gevent.spawn(f,5),gevent.spawn(f,5)])
import gevent from gevent import monkey import urllib.request monkey.patch_all() #monkey.patch_all()给程序打补丁,程序当遇到耗时的代码,会换为gevent中自己实现的模块 def download_img(url): req = urllib.request.urlopen(url) with open(url[-8:],'wb') as file: file.write(req.read()) def main(): gevent.joinall([ gevent.spawn(download_img,"https://assets.ubuntu.com/v1/3887354e-CVE-Priority-icon-High.svg"), gevent.spawn(download_img,"https://www.venustech.com.cn/u/cms/www/202106/11174004guxu.png"), gevent.spawn(download_img,"https://www.baidu.com/img/flexible/logo/pc/result.png")]) if __name__ == "__main__": main()