生成器

1.什么是生成器?
  元组推导式就是生成器
生成器本质是迭代器,允许自定义逻辑的迭代器

迭代器和生成器区别:
迭代器本身是系统内置的.重写不了.
而生成器是用户自定义的,可以重写迭代逻辑

生成器可以用两种方式创建:
(1)生成器表达式 (里面是推导式,外面用圆括号)
(2)生成器函数 (用def定义,里面含有yield)

2.示例代码

# (1) 生成器表达式 (里面是推导式,外面用圆括号)
gen = ( i for i in range(10) )
print(gen)

# 判断类型
from collections import Iterator,Iterable
print(isinstance(gen,Iterator))

# 1.next 调用生成器
print(next(gen))
print(next(gen))

# 2.for + next 调用生成器
for i in range(3):
    print(next(gen))
    
# 3.for 调用生成器所有数据
for i in gen:
    print(i)
   
# 4.list强转生成器,瞬间得到所有数据
gen = ( i for i in range(10) )
print(list(gen))

# print(next(gen)) error  # StopIteration

2. 生成器函数

# yield 类似于 return
共同点在于:执行到这句话都会把值返回出去
不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走
而return直接终止函数,每次重头调用.
yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用

示例代码:

# (1) 基本语法
def mygen():
    print("111")
    yield 1
    
    print("222")
    yield 2
    
    print("333")
    yield 3
   
# 初始化生成器函数  => 返回生成器对象 => 简称生成器
gen = mygen()

# 第一次调用
res = next(gen)
print(res)
# 第二次调用
res = next(gen)
print(res)
# 第三次调用
res = next(gen)
print(res)
# 第四次调用
"""
StopIteration error 
res = next(gen)
print(res)
"""
"""
# 第一次调用
print("111")  yield 1 保存当前第13行代码的状态,把1返回,并且等待下一次调用
# 第二次调用
从上一次保存的位置13行往下走, print("222") yield 2 保存当前第16行代码的状态,把2返回,并且等待下一次调用
# 第三次调用
从上一次保存的位置16行往下走, print("333") yield 3 保存当前第19行代码的状态,把3返回,并且等待下一次调用
# 第四次调用
因为没有更多的yield 返回数据,所有停止迭代.出现报错异常.
"""

# (2) 优化生成器代码
"""生成器应用的场景是在大数据的范围中使用,切记不可直接用for遍历所有,可能无法短时间内获取所有数据"""
def mygen():
    for i in range(1,101):
        yield i
# 初始化生成器函数 => 生成器
gen = mygen()
print("<=====>")
for i in range(30):
    num = next(gen)
    print("我的球衣号码是{}".format(num))

print("<=====>")
for i in range(40):
    num = next(gen)
    print("我的球衣号码是{}".format(num))


# (3) send的使用方式 (给上一个yield发送数据)
"""
# 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")
    
# 初始化生成器函数 => 生成器
gen = mygen()
# 第一次调用生成器
"""
第一次调用生成器时,因为没有遇到yield保存的代码位置,
无法发送数据,默认第一次只能发送None
"""
res = gen.send(None)
print(res,"<==外部==>")

# 第二次调用生成器
res = gen.send("100")
print(res,"<==外部==>")

# 第三次调用生成器
res = gen.send("200")
print(res,"<==外部==>")

# 第四次调用生成器
"""
error
res = gen.send("300")
print(res,"<==外部==>")
图解:

""" """ 使用send调用生成器,第一次发送时必须是None,因为还没有遇到yield保存的代码位置 res = gen.send(None) 走到mygen生成器函数中 print("start") res = yield "内部1" 执行第80行 ,保存退出,记录当前代码位置,将 "内部1" 返回 在98行接受数据 res = "内部1" print(内部1,"<==外部==>") 第二次调用生成器 res = gen.send("100") 把100这个数据发送给上一次代码保存的位置80行进行接受. => 导致 80行 res = 100 打印81行 print(100 ,"<==内部==>") 执行83行 res = yield "内部2" 保存退出,记录当前代码位置,将 "内部2" 返回 执行102行 res = gen.send("100") => "内部2" print("内部2","<==外部==>") .... 依次类推 ... 到第四次调用时, 因为没有更多的yield 返回数据,gen.send(300)无法接受到返回值,所以出现停止迭代 StopIteration的报错,程序终止; """ # (4) yield from 的使用 """将一个可迭代对象变成一个迭代器返回 """ def mygen(): lst = ["张磊","李亚峰","刘一峰","王同培"] yield from lst # 初始化生成器函数 gen = mygen() print(next(gen)) print(next(gen)) print(next(gen)) print(next(gen)) # print(next(gen)) # StopIteration # (5) 斐波那契数列 """使用生成器分段获取所有内容,而不是一股脑的把所有数据全部打印""" """1 1 2 3 5 8 13 21 34 .... """ def mygen(maxval): a,b = 0,1 i = 0 while i < maxval: # print(b) yield b a,b = b,a+b i += 1 # mygen(10) gen = mygen(10) # 第一次获取 for i in range(3): print(next(gen)) # 第二次获取 for i in range(5): print(next(gen))
图解:

 

posted @ 2021-04-07 18:06  urls  阅读(93)  评论(0编辑  收藏  举报