yield
是 Python 中的一个关键字, 这个关键字比较特殊, 用于在任何表达式前, 但它不仅会对其后的表达式有影响, 对整个函数上下文都有影响. 实际上, 凡是在函数体中出现了 yield
关键字, Python 都会对此函数特殊处理, 调用这个函数不再返回值, 而是一个生成器对象.比如
def f():
yield 1
g = f()
print type(g)
<type 'generator'>
next
函数def f():
yield 1
g = f()
print g.next()
yield
, 或者函数的执行过程中反复路过某个 yield
, 那么 next
每次调用会得到下一个产生的值, 比如def f():
yield 1
yield 2
g = f()
print g.next(),
print g.next()
1 2
. 或如下的循环def f():
for x in range(3):
yield x * 2
g = f()
print g.next(),
print g.next(),
print g.next()
next
函数作为返回值... 当然这样来说是不准确地, 如果上面 for
循环如果跑得太快, 那样会疾速产生值导致 next
函数应接不暇, 这样会有诡异的同步问题. 所以正确的语义应该是- 当生成器函数执行到包含
yield
的表达式时, 函数挂起, 并将yield
之后的表达式作为返回值传递给next
函数调用 - 下一次
next
函数调用又会驱动该生成器的函数体继续执行此后的语句, 直到遇见下一个yield
再次挂起并生成一个值交给next
- 如果某次
next
调用驱动了生成器继续执行, 而此后函数正常结束的话, 那么不会有任何值传递给next
函数, 同时, 生成器会抛出StopIteration
异常
def f():
yield 1
g = f()
print g.next(),
print g.next()
return
, 它必须是一句空返回, 即 return
之后不允许跟任何表达式, 这也是限制之一.从下面这个例子可以更好地窥探生成器的执行模式
def f():
print 'a'
yield 1
print 'b'
yield 2
print 'c'
g = f()
print 'start'
print g.next()
print 'next'
print g.next()
print 'end'
start
a
1
next
b
2
end
next
之后, f
函数体的执行就挂起了, 等着下一次调用 next
. 另外, f
中最后一句应该输出的 c
并没有输出, 因为第二次生成器给出了 2
这个值之后就一直处于挂起状态.如果要大慈大悲地让最后一句也执行, 那么需要再加一句
next
调用def f():
print 'a'
yield 1
print 'b'
yield 2
print 'c'
g = f()
print 'start'
print g.next()
print 'next'
print g.next()
print 'end'
g.next()