Python 基础之生成器
一.生成器表达式
生成器本质是迭代器,允许自定义逻辑的迭代器
迭代器和生成器区别:
迭代器本身是系统内置的,重写不了.而生成器是用户自定义的,可以重写迭代逻辑
生成器可以用来钟方式创建:
(1)生成器表达式(里面是推导式 外面是圆括号)
(2)生成器函数 (用def定义,里面含有yield)
#(1) 生成器表达式 generator
#[1,2,3,4] => [4,8,12,16]
#i<< 2 i乘以2的2次幂
gen = (i<<2 for i in range(1,5))
print(gen)
from collections import Iterable,Iterator
print(isinstance(gen,Iterator))
##(1)使用next进行调用生成器
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen )
print(res)
res = next(gen)
print(res)
#res = next(gen ) #StopIteration
#print(res) #越界
##(2)使用for循环调用生成器
gen = (i<<2 for i in range(1,5))
for i in gen:
print(i)
##(3)用for 和next 搭配调用生成器
gen = (i<<2 for i in range(1,5))
for i in range(2):
res = next(gen)
print(res)
二.生成器函数
(用def定义,里面含有yield)
#yield类似于return
共同点在于: 执行到这句话都会把值返回出去
不同点在于: yield每次返回时,会记住上次离开时执行的位置,下次在调用生成器,会从上次执行的位置往下走
而return 直接终止函数,每次重头调用
yield 6 和 yield(6) 2中写法都可以 yield 6 更像 return 6 的写法 推荐使用
from collections import Iterator,Iterable
#(1)基本使用
'''如果函数当中包含了yield,那么这个函数是生成器函数'''
def mygen():
print("one")
yield 1
print("two")
yield 2
print("three")
yield 3
#初始化生成器函数 => 返回一个生成器对象,简称生成器
gen = mygen()
print(isinstance(gen,Iterator))
#调用生成器
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
#res = next(gen)
#print(res)
#代码解析:
首先初始化生成器函数 返回生成器对象 简称生成器
通过next进行调用
第一次调用时候
print(one)
yield 1 记录当前代码执行的位置状态,添加阻塞,暂停在这一行,并返回1,等待下一次调用
第二次调用时候
print(two)
yield 2 记录当前代码执行的位置状态,添加阻塞,暂停在这一行,并返回2,等待下一次调用
第三次调用时候
print(three)
yield 3 记录当前代码执行的位置状态,添加阻塞,暂停在这一行,并返回3,等待下一次调用
第四次调用时候
因为没有yield返回值了 ,所以直接报错..
#(2)优化代码
def mygen2():
for i in range(1,101):
yield "我的球衣号%d" %(i)
#初始化生成器 返回生成器对象 简称生成器
gen2 = mygen2()
for i in range(50):
res = next(gen2)
print(res)
#(3) send 把值发送给一个yield
### send
#next 和 send 区别:
next只能取值
send不但能取值,还能发送值
#send注意点
第一个 send 不能给 yield 传值 默认只写None
最后一个yield 接受不到send 的发送值
#例:
def mygen():
print("start")
res = yield 1
print(res)
res = yield 2
print(res)
res = yield 3
print(res)
print("end")
#初始化生成器函数 返回生成器
send 在一次调用的时候,必须给参数None gen send(None)
是一个硬性要求的语法(因为第一次调用的时候,没有遇到一个yield)
gen = mygen()
res = gen.send(None)
print(res)
res = gen.send(111)
print(res)
res = gen.send(222)
print(res)
# res = gen.send(333)
# # print(res)
#代码解析:
第一个调用时,必须使用gen.send(None)
print(start)
res = yield 1记录当前代码执行的位置状态,添加阻塞并返回1,等待下一次调用
第二次调用时,
send先发送,再返回,发送yield 1 res 接收到了111这个值
print(111)
res = yield 2 记录当前代码执行的位置状态,添加阻塞并返回2 ,等待下一次调用
第三次调用时,
send先发送,再返回,发送yield 2 res接收到222这个值
print(222)
res = yield 3 记录当前代码执行的位置状态 添加阻塞并返回3 ,等待下一次调用
第四次调用时,
因为没有yield继续返回了,直接报错,越界错误
如果仍然想要执行后面没有走完的代码,比如95 96 ,那么要通过try ...except 异常处理来解决
#异常处理格式:
try :
lst = [1,2]
print(lst[99])
execpt:
pass
### yield from :将一个可迭代对象变成一个迭代器返回
#例:
def mygen():
#yield ["陈桂涛","五金玲","张俊林"]
yield from ["陈桂涛","五金玲","张俊林"]
#初始化 一个生成器mygen 返回生成器
gen = mygen()
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
#用生成器写斐波那契数列
#例:
# 1 1 2 3 5 8 13 21 ...
def mygen(n):
a = 0
b = 1
i = 0
while i< n:
#print(b)
yield b
a,b = b,a+b
i+=1
gen = mygen(10000)
for i in range(20):
res = next(gen)
print(res)