python零基础学习2-函数2-生成器(generator)
列表生成式
print([i*2 for i in range(10)]) #[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
缺点: 一次生成元素较多的列表, 占用内存较大
解决方案: 在使用过程中依次生成
生成器
使用列表生成式创建生成器:
b=(i*2 for i in range(10)) #产生一个生成器, 但是并没有元素 print(b) #<generator object <genexpr> at 0x0000006E78879308> for i in b: print(i) #可正常打印
- 生成器只能通过循环调用, 生成元素, 不能使用b[100], 切片等功能
- b.__next__() 可以求下一个, 但无法回到上一个
- 生成器只能记住当前元素, 之前的元素不保存
使用函数创建生成器:
示例: 斐波那契数列
使用函数实现
#使用函数实现 def fib(max): n,a,b=0,0,1 while n<max: print(b) a,b=b,a+b #这种赋值方式, 相当于先将b, a+b赋值给临时变量, 再同时赋给a,b n=n+1 return "done" fib(10)
使用生成器实现
#改造为生成器 def fib(max): n,a,b=0,0,1 while n<max: yield b #只要有yield就是生成器 a,b=b,a+b n=n+1 return "done" #异常打印信息 fib_gen=fib(4) #调用方法 # print(fib_gen.__next__()) # print(fib_gen.__next__()) # print(fib_gen.__next__()) # print(fib_gen.__next__()) # print(fib_gen.__next__()) #next超出范围时会抛出异常 #防止超出范围的调用方法 while True: try: x=fib_gen.__next__() print(x) except StopIteration as e: print(e.value) #打印值为done break
实际应用: 可通过yield实现单线程下并发的功能
示例(异步I/O的雏形):
import time def consumer(name): print(name,"开始消费~") while True: baozi=yield print(baozi,"被",name,"吃了~") def producer(name): c1=consumer("A") #生成两个生成器 c2=consumer("B") c1.__next__() #第一次执行, 打印开始消费, 之后停在yield处, 不执行 c2.__next__() for i in range(10): time.sleep(2) print(name,"做了两个包子") c1.send(i+1) #给yield传值, 并执行baozi=yield, 继续执行 c2.send(i+1) producer("alex")
迭代器
- 可直接作用于for循环的数据类型: 列表, 字段, 元组, 集合, 字符串, 生成器. 统称为可迭代对象(Iterable)
- 可以被__next__()函数调用并不断返回下一个值的对象统称为迭代器(Iterator), 没数据时抛出StopIteration异常
- 可使用isintance()判断
from collections import Iterable from collections import Iterator print(isinstance([],Iterable)) #True print(isinstance([],Iterator)) #False print( isinstance((x for x in range(10)),Iterator)) #True
- 生成器都是迭代器, 但list, dict, str虽然是可迭代对象, 但并不是迭代器
- 可使用iter()将可迭代对象变为迭代器
a=[1, 2, 3] b=iter(a) print(b.__next__()) print(b.__next__()) print(b.__next__())
迭代器特征:
- 表示一个数据流, 不能提前知道序列长度
- 计算是惰性的
- 甚至可以表示无限大的数据流, 例如全体自然数
range(0,10)也是迭代器
浙公网安备 33010602011771号