生成器
- 通过列表生成式, 可以直接生成一个列表. 但是受到内存限制, 列表容量是有限的. 如果创建一个包含100万个元素的列表, 却只需要访问其中几个, 空间就浪费了.
- 如果列表元素可以按照某种算法算出来, 在循环的过程中不断推算出后续的元素, 这样就不必创建完整的list,从而节省大量空间. 在Python中, 这种一边循环一边计算的机制, 称为生成器: generator.
创建一个generator, 有很多种方法
- 第一种方法: 把一个列表生成式的 [ ] 改成 (), 就创建了一个generator
-
1 >>> L = [x*x for x in range(10)] 2 >>> L 3 4 >>> g = (x*x for x in range(10)) 5 >>> g
-
1 #!/usr/bin/python 2 # -*- coding: utf-8 -*- 3 4 a = [] 5 for i in range(10): 6 a.append(i*2) 7 8 print(a) 9 10 11 print("========== 上述代码等效于下面这句 ========== ") 12 b = [i*2 for i in range(10)] 13 print(b) 14 15 16 print("============== 更进阶写法 ============== ") 17 c = [func(i) for i in range(10)] 18 print(c)
-
- 注: 其实生成器产没有直接把数据都计算出来, 只是生成了一个地址, 这个地址包含的是计算的方法(下图方法2).调用的时候才会开始产生值.
-
生成器只有调用的时候才会生成一个个的值, 所以直接像列表一样取某个位置上的值是不行的. 所以生成器是不支持列表的切片等值的.只能通过循环取出具体的值.
- 生成器只记住当前的位置, 是没有办法往回取值的(比如打了两个__next__()之后想取前边第一个值,是不行的).只能取下一个值.
- 第二种方法, 用一个函数做生成器
- 斐波那契数列 (要在哪里返回数据,就在哪里用yield. yield保存了函数中断的点,一旦调用__next__方法, 函数又会从中断点开始继续执行)
-
1 # !/user/bin/python 2 # -*- coding: utf-8 -*- 3 4 def fib(max): 5 n,a,b = 0,0.1 6 while n<max: 7 print(b) 8 a,b = b, a+b 9 n = n + 1 10 return 'done' 11 12 fib(10) 13 14 15 16 # 生成器 17 def fib(max): 18 n,a,b = 0,0.1 19 while n<max: 20 yield b 21 a,b = b, a+b 22 n = n + 1 23 return 'done' 24 25 print(fib(10)) # 因为fib()是个生成器, 这样只能打印出一个地址. 要想打印出数值,需要用循环,或者___next___() 26 27 f=fib(100) 28 print(f.__next__()) # 这种方式 ,可以在循环中断在某个地方做些其它的事再回来. 29 print('============') 30 print(f.__next__()) 31 32 print('======================== loop ========================') 33 for i in f: 34 print(i) # 不会从头开始打印,因为前面有两个print(f.__next__())
- 抓取异常
-
1 # !/user/bin/python 2 # -*- coding: utf-8 -*- 3 4 def fib(max): 5 n,a,b = 0,0.1 6 while n<max: 7 print(b) 8 a,b = b, a+b 9 n = n + 1 10 return 'done' 11 12 fib(10) 13 14 15 16 # 生成器 17 def fib(max): 18 n,a,b = 0,0.1 19 while n<max: 20 yield b 21 a,b = b, a+b 22 n = n + 1 23 return 'done' 24 25 print(fib(10)) # 因为fib()是个生成器, 这样只能打印出一个地址. 要想打印出数值,需要用循环,或者___next___() 26 27 f=fib(100) 28 print(f.__next__()) # 这种方式 ,可以在循环中断在某个地方做些其它的事再回来. 29 print('============') 30 print(f.__next__()) 31 32 print('======================== loop ========================') 33 for i in f: 34 print(i) # 不会从头开始打印,因为前面有两个print(f.__next__()) 35 36 37 # 抓取异常 38 f=fib(10) 39 g=fib(6) 40 while True: 41 try: 42 x = next(g) 43 print('g: ', x) 44 except StopIterration as e: 45 print('Generator return value: ', e.value) 46 break
-
- 斐波那契数列 (要在哪里返回数据,就在哪里用yield. yield保存了函数中断的点,一旦调用__next__方法, 函数又会从中断点开始继续执行)
生成器并行运算
1 # !/user/bin/python 2 # -*- coding: utf-8 -*- 3 import time 4 5 def consumer(name): 6 print('%s 准备吃包子了' %name) 7 while True: 8 baozi = yield 9 print('包子[%s] 来了, 被[%s]吃了' %(baozi, name)) 10 11 12 c = consumer('lucy') 13 c.__next__() # 输出第一个print的内容 print('%s 准备吃包子了' %name) 14 c.__next__() # 输出第二个print的内容, print('包子[%s] 来了, 被[%s]吃了' %(baozi, name)) 15 b1 = '韭菜' 16 c.send(b1) # 把包子的参数传过去,被yield接收到,传给baozi. # 返回包子[韭菜] 来了, 被[lucy]吃了 17 18 ''' 19 send和next的区别: send唤醒生成器继续打印,并且会把参数传给yield; next只能唤醒生成器, 不能传值. 20 ''' 21 22 # 单线程下的并行交换, 也叫携程. 23 24 def producer(name): 25 c = consumer('A') 26 c2 = consumer('B') 27 c.__next__() 28 c2.__next__() 29 print('老子开始准备做包子了') 30 for i in range(10): 31 time.sleep(1) 32 print('做了1个包子,分两半') 33 c.send(i) 34 c2.send(i) 35 36 37 producer('alex')
迭代器
可直接作用于for循环的数据类型有以下几种:
a. 一类是集合数据类型, 如list, tuple, dict, set, str等
b. 一类是generator, 包括生成器和带yield的generator function
这些可以直接作用于for循环的对象统称为可迭代对象: Iterable.
可以用例isinstance()判断一个对象是否是Iterable对象.
1 from collections import Iterable 2 3 isinstance([],Iterable) 4 isinstance({ },Iterable) 5 isinstance('AB',Iterable) 6 isinstance((x for x in range(10)), Iterable) 7 isinstance(100, Iterable)
生成器不但可以作用于For循环, 还可以被next() 函数不断调用 并返回下一个值, 直到最后抛出StopIteration错误表示无法继续返回下一个值了.
可以被next()函数调用并不断返回下一个值的对象称为换代器: Iterator.
可以使用isInstance()判断一个对象是否是Iterator对象:
1 from collections import Iterable 2 3 isinstance([],Iterable) # True 4 isinstance({ },Iterable) # True 5 isinstance('AB',Iterable) # True 6 isinstance((x for x in range(10)), Iterable) # True 7 isinstance(100, Iterable) # True 8 9 10 from collections import Iterator # (没有__next()__方法就不是迭代器): 11 isinstance((x for x in range(10)), Iterator) # True 12 isinstance([], Iterator) # False 13 isinstance((), Iterator) # False 14 isinstance('ab', Iterator) # False 15 16 17 ''' 18 生成器都是Iterator对象, 但list, dict, str是Iterable, 却不是Iterator. 19 把list, dict, str等Iterable变成Iterator可以使用iter()函数 20 '''