yield(自定迭代器)
若函数体包含yield
关键字,再调用函数,并不会执行函数体代码,得到的返回值是一个生成器对象也叫自定义迭代器,
def index():
print('Hello World_1')
yield 'hhhh_1'
print('Hello World_2')
yield 'hhhh_2'
print(index) # 普通函数
# <function index at 0x7fd9168c5ea0>
print(index()) # 迭代器
# <generator object index at 0x7ff534fd3a40>
res = index()
print(next(res))
# Hello World_1
# hhhh_1
print(next(res))
# Hello World_2
# hhhh_2
补充:
- 没有调用之前,只是一个普通的函数
- 加括号调用并接受结果,不执行代码,只是变成了生成器对象(迭代器)
- 当变成生成器对象(迭代器),可以通过
__next__
取值 - 当函数题代码存在多个
yield
关键字,调用一次__next__
将会执行代码,并返回yield
关键字,后面的值让代码停留在yield
位置,再次调用也是一样的 - 当没有可执行代码,再次执行则会报错
StopIteration
yield表达式作用
作用
- 在函数体代码中出现,可以将函数变成生成器
- 在执行过程中,可以将后面的值返回出去,类似于
return
- 可以暂停住代码的运行
- 可以接收外界的传值
使用
def index(name):
print(f"Hello, {name}")
while True:
word = yield
print(f"Hello, {word}! --{name} ")
res = index('kevin')
res.__next__()
# Hello, kevin
res.send('world') # send可以给yield传值,并且自动调用一次__next__方法
# Hello, world! --kevin
res.send('hacker') # send可以给yield传值,并且自动调用一次__next__方法
# res.send('hacker')
生成器表达式(元组推导式)
元组推导式和列表推导式的用法也完全相同,只是元组推导式是用 () 圆括号将各部分括起来,而列表推导式用的是中括号 [],另外元组推导式返回的结果是一个生成器对象。
定义
res = (表达式 for 变量名 in 循环对象)
或
res = (表达式 for 变量名 in 循环体对象 if 条件 )
使用
res = (i for i in range(10))
print(res) # # 返回的是生成器对象
# <generator object <genexpr> at 0x7f85ab2c0a40>
print(next(res)) # 通过next取值
# 0
print(next(res))
# 1
print(next(res))
# 2
print(next(res))
# 3
print(next(res))
# 4
print(next(res))
# 5
自定义range方法
# 通过生成器模拟range方法
def my_range(start=0, end=None, step=1):
if not end:
end, start = start, 0
while start < end:
yield start
start += step
for j in my_range(8):
print(j)
笔试题
def add(n, i):
return n + i
def test():
for i in range(4):
yield i
g = test()
for n in [1, 10]:
g = (add(n, i) for i in g)
res = list(g)
print(res)
# A. res=[10,11,12,13]
# B. res=[11,12,13,14]
# C. res=[20,21,22,23]
# D. res=[21,22,23,24]