一 . 生成器
1.介绍
通过列表生成式,可以直接创建一个列表,但是受内存限制,列表容量是有限的。
a = [i*2 for i in range(10000)
print (a)
如果列表元素可以按照某种算法推算出来,是否可以在循环的过程中不断推算出后续的元素?
这样就不必创建完整的list,从而俭省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器,generator.
a = (i*2 for i in range(10000))
for i in a:
print (i)
generator比较强大,但是如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
比如:斐波那契数列,除了第一个和第二个数之外,任意的数都可有前面两个数相加得到(1,1,2,3,5,8,......)
1 def fib(max): 2 n, a, b = 0, 0, 1 3 while n < max: #n只是控制循环 4 print(b) 5 a, b = b, a + b 6 7 # 相当于:t = (b, a + b) (t是一个元组) 8 # a = t[0] 9 # b = t[1] 10 #不等价于下面的 11 #a = b a = 1,b = 2,a = b, a = 2 12 #b = a +b ,b = 2 + 2 = 4 13 14 n=n+1 15 return 'done' 16 fib(100) #生成100斐波那契数
1 def fib(max): 2 n, a, b = 0, 0, 1 3 while n < max: #n只是控制循环 4 #print(b) 5 yield b #就变成生成器了 6 a, b = b, a + b 7 8 # 相当于:t = (b, a + b) (t是一个元组) 9 # a = t[0] 10 # b = t[1] 11 #不等价于下面的 12 #a = b a = 1,b = 2,a = b, a = 2 13 #b = a +b ,b = 2 + 2 = 4 14 15 n=n+1 16 return 'done' #异常的时候打印的一个信息 17 f = fib(10) #生成100斐波那契数 18 print(f.__next__()) 19 print(f.__next__()) 20 print("_________") #函数想停就停,随意进出 21 print(f.__next__()) 22 print(f.__next__()) 23 print(f.__next__()) 24 print("=====star loop======") 25 for i in f: 26 print(i)
补充:
异常捕捉;
还可以通过yield 实现在单线程的情况下实现并发运算的效果。
1 import time 2 def consumer(name): #消费者 3 print("%s 准备吃包子啦!" %name) 4 while True: 5 baozi = yield 6 7 print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) 8 9 c = consumer("xiaolai") 10 c.__next__() #只是为了打印print("%s 准备吃包子啦!" %name) 11 12 def producer(name): #生产者 13 c = consumer('A') 14 c2 = consumer('B') 15 c.__next__() 16 c2.__next__() #唤醒yield 17 print("老子开始准备做包子啦!") 18 for i in range(10): 19 time.sleep(1) 20 print("做了1个包子,分两半!") 21 c.send(i) 22 c2.send(i) #唤醒yield并且传值 23 24 producer("shogou")
2.说明:
生成器,只有在调用时才会生成相应的数据。(只能用循环,不能像列表一样去切片))
只记住当前位置;
只有一个 .__next__方法。 (2.X版本中next())
二. 迭代器
可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型:list , tuple ,dict ,set ,str等;
一类是generator,包括生成器和带yield的generator function.
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable.
可以使用isinstance() 判断一个对象是否是Iterable对象:
>>>from collections import Iterable
>>>isinstance([], Iterable)
True
生成器不但可以作用于for循环,还可以被__next__()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
可以被__next__()函数调用并不断返回下一个值的对象称为迭代器:Iterator.(是迭代器就有__next__()方法)
>>>from collections import Iterator
>>>isinstance([], Iterator )
False
生成器都是Iterator对象,但list, dict ,str 虽然是Iterable,却不是Iterator。把list, dict ,str 等Iterable变成Iterator可以使用iter()函数:
a=[1,2,3]
type (a)
b = iter(a)
b.__next__()
小结:
Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算,Iterator甚至可以表示一个无限大的数据流,例如全体自然数。使用list是永远不可能存储全体自然数的 。