# **************************************************************************
# Python学习
# **************************************************************************
# ** 所属主题: 函数
# ** 所属分层: 34 生成器
# ** 功能描述: 34 生成器
# ** 创 建 者: 陈红伟
# ** 创建日期: 2021/4/13 11:47 下午
# **************************************************************************
# ** 修改日期 修改人 修改内容
# ** 2021/4/13 陈红伟 新增学习内容代码
# **************************************************************************
def func():
return 1
return 2
return 3
return 4
# 上述只能返回一个值1,那如果想返回多次值呢? ==== yield
# 如何得到自定义的迭代器: 生成器 就是 迭代器
# 在函数内一旦存在yield关键字,调用函数并不会执行函数体代码,会生产一个生成器对象,生成器即自定义的迭代器
def func():
print("第1次")
yield 1
print("第2次")
yield 2
print("第3次")
yield 3
print("第4次")
g = func()
print(g) # generator:生成器
res = g.__next__() # 第1次
#上行代码 会运行函数体代码,直到遇到yield就停下来
# 想看到此时的返回值
print(res) # 1
res2 = next(g) # 第2次 注意⚠️:g.__next__() 和 next(g)的用法是一样的
print(res2) # 2
res3 = g.__next__() # 第3次
print(res3) # 3
# res4 = g.__next__() # 继续执行程序(所以会打印出" 第4次")并抛出异常如下:
# 第4次
# Traceback (most recent call last):
# File "/Users/chenhongwei/PycharmProjects/python-learn/Egon202003/01 python基础/34 生成器.py", line 50, in
# res4 = g.__next__()
# StopIteration
# 小知识:
# g.__next__() 和 next(g)的用法是一样的
# len('q') 和 'q'.__len__()的用法也是一样的;还有很多函数有类似的用法
print(len('q')) # 1
print('q'.__len__()) # 1
# 应用案例:写一个不占用内存空间的函数,就是模仿写个range()函数
def my_range(start,stop,step=1):
print('start...')
while start<stop:
start+=step
# return start
yield start #不能用return,不然就退出函数了,所以用yield。
print('end...')
for n in my_range(1,7,2):
print(n)
# start...
# 3
# 5
# 7
# end...
# 在后面学到【并发编程】的时候可以更深的体现yield作用:运行挂起。
# yield表达式: x = yield 返回值
# 是要有yield该函数就是生成器
def dog(name):
print(f'{name}准备吃东西')
while True:
x = yield None # x 是拿到yield接收到的值,可以通过send()传入值
print(f'{name}吃了{x}')
g = dog('xiaolan')
next(g) # xiaolan准备吃东西
"""
send()可以为yield赋值,并继续运行
"""
g.send('骨头 ') # xiaolan吃了骨头
g.send('') # xiaolan吃了
g.send('小匣子') # xiaolan吃了小匣子
# g.send('1','2') # TypeError: send() takes exactly one argument (2 given) # 只需要一个参数,但你传入了两个值
g.send(['gutou','xiaoyugan']) # xiaolan吃了['gutou', 'xiaoyugan']
"""
还可以关闭,关闭后无法传值
"""
g.close()
# g.send(1) # StopIteration 已关闭,无法再传值
# yiled在程序中的执行情况:
def func():
list1 = []
print('start....')
x = yield list1
print('proceding.....',x)
list1.append(x)
y = yield list1
print(y)
g = func()
# g.send(1) # TypeError: can't send non-None value to a just-started generator 必须先初始化,在使用send之前
res = g.__next__()
# start.... 运行到115行,然后返回结果给res。此时结果为yield后面定义的返回值,此处即为list1,并且yield是没有执行的,所以yield是None,x也是,没有被赋值的
print(res)
# [] 因为此时结果为yield后面定义的返回值,此处即为list1,所以是返回[]
# g.send() # TypeError: send() takes exactly one argument (0 given) send必须要给予参数
res2 = g.send(1111) # 此时会在上次停在yield的位置继续运行,此时第1个yield的值是1111,并且此时x=1111,此时返回值为:list1.append(x) ,此处即为[1111]。并且第二个yield为None。
# proceding..... 1111
print(res2)
# [1111]
# res = g.send(3333) # StopIteration 因为后面没有第三个yield了,所以报错