Python yield小记
written on Sun 27 March 2016 by importcjj
yeild
yield 一般搭配函数来定义一个Generator(生成器)
一个简单的例子:
def f():
print "Today is 7.21"
yield 6
f() 将会返回一个Generator, 而非像普通函数一样执行。想要使用生成器的话(比如 i)需要使用i.next() (与next(i)等效) 和i.send(value)。
>>> i = f()
>>> i
<generator object f at 0x1041e7dc0>
>>> i.next()
Today is 7.21
6
>>> i.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
生成器调next()或send()方法后会执行函数体内的语句,执行到yield语句后停止, 并返回yield语句的参数,上例中就是 6。再次使用next()或send()会从停止处继续执行,由于之后已经没有yield了,所以会raise StopTteration异常。
有时候可能会遇到这样的情况
def f():
m = 5
m = yield 6
print "m = ", m
上例中 m 会得到(yield 6)这个式子的值。那么,这个值是多少呢?取决于i.next()和i.send(value)。如果是next,则是None。send的话就是value。
can't send non-None value to a just-started generator 第一次调用只能是 i.next()或者i.send(None)
这里需要注意一点,第一次next会在执行(yield 6)后停止,并不会执行m的赋值(重新绑定,毕竟python不太一样)。m的值是轮到下一个next或send来改变的。
>>> def f():
... m = 5
... m = yield 6
... print "m = ", m
...
>>> i = f()
>>> i.next()
6
>>> i.send(7)
m = 7
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
使用
def fibonacci(i):
"""关于斐波那契数列的生成器
"""
if i < 0:
raise ValueError, i
if i == 0:
yield 0
count = 0
a, b = 0, 1
while count <= i:
yield a
a, b = b, a + b
count += 1
>>> for i in fibonacci(13):
... print i,
...
0 1 1 2 3 5 8 13 21 34 55 89 144
>>> for i in fibonacci(-1):
... print i,
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "_yield.py", line 5, in fibonacci
raise ValueError, i
ValueError: -1
>>> for i in fibonacci(0):
... print i,
...
0
>>> for i in fibonacci(1):
... print i
...
0 1
随便写了一个关于斐波拉切数列的生成器,并且遍历了它。
终止生成器
fib = fibonacci(6)
fib.close()
fib.throw(GeneratorExit)
# GeneratorExit 继承自 BaseException
使用这两种方法之后,再去访问生成器的方法,会触发StopIteration异常。遍历的话也不会返回有效值。
最后
关于yield暂时只想到这些,以后可能补充。生成器不一定还能通过别的方式定义。比如
(i for i in range(6))