python生成器:send、yield from等用法
一边循环一遍计算的机制,称为生成器。
优点:不需要创建完整的list,从而节省内存控件。
如果一个函数中包含yield关键字,那么这个函数是一个generator。调用该函数就是创建了一个generator对象。生成器只会在响应迭代操作时才运行。
def increment(start, stop, step):
x = start
while x < stop:
yield x
x += step
a = increment(0, 2, 0.5)
print(a)
结果:
<generator object increment at 0x0000028CD9A07C10>
yield相当于return返回一个值,并且记住这个返回的位置。下次迭代时,代码从yield的下一条语句开始执行。
for n in increment(0, 2, 0.5):
print(n)
结果:
0 # 第一次返回时没有执行 x += step
0.5
1.0
1.5
除了通过for循环可以迭代,也可通过其他可以访问可迭代对象中元素的函数,例如sum()、list()
print(sum(increment(0, 2, 0.5)))
print(list(increment(0, 2, 0.5)))
结果:
3.0
[0, 0.5, 1.0, 1.5]
生成器send()用法
def increment(start, stop, step):
x = start
while x < stop:
y = yield x
x += step
yield y
a = increment(0, 2, 0.5)
print(next(a)) # 0
print(a.send("new value")) # new value
print(next(a)) # 0.5
print(next(a)) # None
a = yield x send()的作用是使y赋值为send的参数,然后让生成器执行到下一个yield
next(a)启动了生成器,yield x返回0
使用send()方法,执行yield x后的代码y=,把send()内的参数new value赋值给y,遇到yield y时把y返回
第三个next()执行了y = yield x,因为不是send(),并没有给y赋值
第四个next()执行了yield y,因为上一部没有给y赋值,所以输出为None
总结:
-
使用next()时,只会调用一次yield,下一次使用next()则执行yield之后的语句
-
使用send()时,则会把send()的内参数赋值给yield的赋值对象,然后让生成器执行到下一个yield
-
如果生成器内仅有一个yield,则send()的作用与next()相同
def increment(start, stop, step): x = start while x < stop: x += step yield x a = increment(0, 2, 0.5) print(a.send(None)) print(a.send("new value")) print(next(a)) print(a.send("new value")) print(next(a))
结果:
0.5 1.0 1.5 2.0 Traceback (most recent call last): File "D:\personal\python_fundamental\generator_try\main.py", line 29, in <module> print(next(a)) StopIteration
yield from用法
yield from后需要加上可迭代对象,可以把可迭代对象中的元素一个一个yield出来
# yield from
def yield_from():
li = [1, 2, 3]
yield from li
a = yield_from()
print(a.__next__())
print(a.__next__())
print(a.__next__())
结果:
1
2
3
# yield
def yield_from():
li = [1, 2, 3]
yield li
a = yield_from()
print(a.__next__())
print(a.__next__())
print(a.__next__())
结果:
[1, 2, 3]
Traceback (most recent call last):
File "D:\personal\python_fundamental\generator_try\yield_from.py", line 8, in <module>
print(a.__next__())
StopIteration