标签:__ 迭代 Iterator Python 生成器 next print isinstance
1.生成器
列表生成式:
1 l = [i*2 for i in range(10)] 2 print(l)
通过列表生成式,可以直接创建一个列表,但是收到内存限制,列表容量是有限的。如果创建一个包含100w元素的列表,而我们只需要访问前面几个元素,那么就太占用空间了。如果列表元素可以按照某种算法推算出来,我们是否可以在循环过程中不断推算出后续元素呢,这样就不必创建完整的list,从而节省大量的空间,这样一边循环一边计算的机制称为生成器:generator。
1.1 创建生成器
第一种方式:把列表生成式的[]改成()就可以
1 l = [i*2 for i in range(10)] 2 print(l) 3 4 l = (i*2 for i in range(10)) 5 print(l) 6 7 运行结果: 8 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 9 <generator object <genexpr> at 0x000001BA440C35E8>
第二种方式:yield方式
斐波那契数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到:1,1,2,3,5,8,13,21,34...
1 def fib(max): 2 n,a,b = 0,0,1 3 while n<max: 4 print(b) 5 a,b = b,a+b 6 n = n+1 7 return 'done' 8 9 fib(5) 10 11 运行结果: 12 1 13 1 14 2 15 3 16 5
解析:a,b = b,a+b
相当于如下所示:
1 a,b = 0,1 2 t = (b,a+b) #t是一个tuple 3 a = t[0] 4 b = t[1] 5 print(a,b) 6 7 运行结果: 8 1,1
把上面案例中的print(b)改成yield b就变成了一个生成器。
1 def fib(max): 2 n,a,b = 0,0,1 3 while n<max: 4 yield b 5 a,b = b,a+b 6 n = n+1 7 return 'done' 8 9 fib(5) #此时这里就没有输出内容了,因为已经变成了一个生成器,可以通过__next__()取值 10 print(fib(5)) 11 12 运行结果: 13 <generator object fib at 0x00000257090E35E8>
取值:
1 def fib(max): 2 n,a,b = 0,0,1 3 while n<max: 4 yield b 5 a,b = b,a+b 6 n = n+1 7 return 'done' #异常的时候打印的消息 8 9 t=fib(5) 10 print(fib(5)) 11 for i in t: #使用for循环不会报StopIteration异常 12 print(i)
使用__next__()超过范围会报错StopIteration,如下
1 def fib(max): 2 n,a,b = 0,0,1 3 while n<max: 4 yield b 5 a,b = b,a+b 6 n = n+1 7 return 'done' 8 9 t=fib(5) 10 print(t.__next__()) 11 print(t.__next__()) 12 print(t.__next__()) 13 print(t.__next__()) 14 print(t.__next__()) 15 print(t.__next__()) 16 17 运行结果: 18 1 19 1 20 2 21 3 22 5 23 Traceback (most recent call last): 24 File "D:/Python/Project/python3.5/test.py", line 15, in <module> 25 print(t.__next__()) 26 StopIteration: done
异常捕获并观察return后面的值:
1 def fib(max): 2 n,a,b = 0,0,1 3 while n<max: 4 yield b 5 a,b = b,a+b 6 n = n+1 7 return 'done' 8 9 t=fib(5) 10 while True: 11 try: 12 x = t.__next__() 13 print(x) 14 except StopIteration as e: 15 print('异常信息:',e.value) 16 break 17 18 运行结果: 19 1 20 1 21 2 22 3 23 5 24 异常信息: done
案例:使用yield在单线程的情况下实现并行运算的效果
首先搞清楚__next__()和send()方法的区别:
1 def gen(name): 2 print("%s在排队!"%name) 3 while True: 4 a = yield 5 print("[%s]来了,[%s]上车了!"%(a,name)) 6 7 t = gen("Tom") 8 t.__next__() 9 t.__next__() 10 #next运行生成器,并不给yield赋值 11 t.send("公交车") 12 #send运行生成器并给yield赋值 13 14 运行结果: 15 Tom在排队! 16 [None]来了,[Tom]上车了! 17 [公交车]来了,[Tom]上车了!
案例开始:
import time def consumer(name): print("%s准备吃包子啦!"%name) while True: baozi = yield print("包子[%s]来了,被[%s]吃了!"%(baozi,name)) def producer(name): c = consumer('A') c.__next__() print("开始做包子啦!") for i in range(3): time.sleep(1) print("%s做了2个包子!"%name) c.send(i) producer('Andy') ''' 运行结果: A准备吃包子啦! 开始做包子啦! Andy做了2个包子! 包子[0]来了,被[A]吃了! Andy做了2个包子! 包子[1]来了,被[A]吃了! Andy做了2个包子! 包子[2]来了,被[A]吃了! '''
生成器总结:
生成器只有在调用时才会生成相应的数据。
生成器只记录当前位置,只能向后取数据(__next__()),不能向前取数据。
创建一个generator后,基本上不会用__next__()调用,而是通过for循环来进行迭代,并且不需要关心StopIteration的错误。
2.迭代器
可以直接作用于for循环的数据类型如下:
- 集合数据类型:list、tuple、dict、set、str等
- generator:包括生成器和带yield的generator函数
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以使用isinstance()判断一个对象是否是Iterable对象。
1 from collections import Iterable 2 3 4 print(isinstance([],Iterable)) 5 print(isinstance((),Iterable))
生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象:
1 from collections import Iterator 2 3 4 print(isinstance([],Iterator)) 5 print(isinstance("",Iterator)) 6 print(isinstance((i for i in range(10)),Iterator)) 7 8 运行结果: 9 False 10 False 11 True
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
1 from collections import Iterator 2 3 4 print(isinstance(iter([]),Iterator)) 5 print(isinstance(iter(""),Iterator)) 6 print(isinstance((i for i in range(10)),Iterator)) 7 8 运行结果: 9 True 10 True 11 True
标签:__,迭代,Iterator,Python,生成器,next,print,isinstance 来源: https://www.cnblogs.com/jmwm/p/10512284.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。