专栏名称: dwzb
目录
相关文章推荐
51好读  ›  专栏  ›  dwzb

yield全面总结

dwzb  · 掘金  ·  · 2018-03-14 05:55

正文

yield全面总结

本文首发于 知乎
yield生成器在python中使用广泛,更是python中协程的实现原理,有必要深入掌握。

本文分为如下几个部分

  • 简单yield的使用
  • yield空
  • yield from
  • send与yield赋值
  • return yield

简单yield的使用

下面是一个最简单的yield使用的例子

def myfun(total):
for i in range(total):
yield i

定义了 myfun 函数,调用时比如 myfun(4) 得到的是一个生成器,生成器有3种调用方式

1.用next调用

>>> m = myfun(4)
>>> next(m)
0
>>> next(m)
1
>>> next(m)
2
>>> next(m)
3
>>> next(m)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

每次调用一次 next ,函数都会执行到 yield 处停止,等待下一次 next next 次数超出限制就会抛出异常

2.循环调用

for i in myfun(4):
print(i)

运行结果为

0
1
2
3

生成器是可迭代对象,可以用循环调用。循环调用就是最大限度地调用 next ,并返回每次 next 运行结果

这就是yield的最基本使用,下面来应用一下

python内置模块itertools中实现了一些小的生成器,我们这里拿 count 举例子,要实现下面这样的效果

>>




    
> from itertools import count
>>> c = count(start = 5, step = 2)
>>> next(c)
5
>>> next(c)
7
>>> next(c)
9
>>> next(c)
11
......

实现如下

def count(start, step = 1):
n = 0
while True:
yield start + n
n += step

3.循环中调用 next

下面循环中调用 next ,用 StopIteration 捕获异常并退出循环

>>> m = myfun(4)
>>> while True:
... try:
... print(next(m))
... except StopIteration:
... break
...
0
1
2
3

yield空

yield空相当于一个中断器,循环运行到这里会中断,用于辅助其他程序的执行。也可以理解成返回值是 None ,我们来看下面这个例子

>>> def myfun(total):
... for i in range(total):
... print(i + 1)
... yield
...
>>> a = myfun(3)
>>> next(a)
1
>>> next(a)
2
>>> next(a)
3
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> a = myfun(3)
>>> for i in a:
... print(i)
...
1
None
2
None
3
None

yield from

通过下面一个例子来展示 yield from 的用法

def myfun(total):
for i in range(total):
yield i
yield from ['a', 'b', 'c']

next 调用结果如下

>>> m = myfun(3)
>>> next(m)
0
>>> next(m)
1
>>> next(m)
2
>>> next(m)
'a'
>>> next(m)
'b'
>>> next(m)
'c'
>>> next(m)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

上面的函数相当于

def myfun(total):
for i in range(total):
yield i
for i in ['a', 'b', 'c']:
yield i

下面我们也做一个小练习,实现itertools模块中的 cycle ,效果如下

>>> from itertools import cycle
>>> a = cycle('abc')
>>> next(a)
'a'
>>> next(a)
'b'
>>> next(a)
'c'
>>> next(a)
'a'
>>> next(a)
'b'
>>> next(a)
'c'
>>> next(a)
'a'

实现如下

def cycle(p):
yield from p
yield from cycle(p)

send与yield赋值

先讲 send ,首先明确一点, next 相当于 send(None) ,还是看下面最简单的例子

>>> def myfun(total):
... for i in range(total):
... yield






请到「今天看啥」查看全文