<p>我终于弄明白了,尽管它需要对<code>pair</code>和其他转换进行一些更改。你知道吗</p>
<p>停止计算并随后恢复计算的唯一方法是<code>yield</code>。因此,如果我们用某种形式的<code>yield</code>替换<code>input_generator.next()</code>,我们就可以控制向转换提供值的速度。你知道吗</p>
<p>首先我定义一个请求对象</p>
<pre><code>class Get(object):
def isset(self):
return hasattr(self, 'value')
def set(self, x):
self.value = x
</code></pre>
<p>我现在将<code>n = foo.next()</code>替换为</p>
<pre><code>g = Get()
yield g
if not g.isset():
break
n = g.value
</code></pre>
<p>例如,我的问题中的<code>pair</code>将变成</p>
<pre><code>def pair(): #notice that there isn't an input generator any more
prev = None
while True: #there was a next() hidden inside 'for'
g = Get()
yield g
if not g.isset():
break
elif prev:
yield (prev, g.value)
prev = None
else:
prev = g.value
</code></pre>
<p>这种变换很容易转化为适当的变换</p>
<pre><code>def withGen(fn, gen):
for f in fn: #get the next request or result
if isinstance(f, Get):
f.set(gen.next()) #answer requests with gen.next()
else:
yield f #yield results
print [x for x in withGen(pair(), [1, 2, 3, 4].__iter__())]
#prints [(1, 2), (3, 4)]
</code></pre>
<p>最后我们可以定义<code>withSelector</code></p>
<pre><code>def withSelector(select, fn):
f = None #we need to remember the last unanswered request
while True:
if not f: #if last request has been answered...
f = fn.next() #get the next request, or the result
if isinstance(f, Get): #if it's a request...
g = Get()
yield g #ask for another input value
if not g.isset():
break
elif select(g.value): #if the values matches selector...
f.set(g.value) #feed it to transformation
f = None #and mark the request as answered
else:
yield g.value #otherwise just yield it
else: #if transformation yielded a result
yield f #yield it
f = None #and note that there is no request waiting
arr = range(1, 18)
print [x for x in withGen(withSelector(isEven, pair()), arr.__iter__())]
#prints [1, 3, (2, 4), 5, 7, (6, 8), 9, 11, (10, 12), 13, 15, (14, 16), 17]
</code></pre>
<p>我甚至可以排序两个选择器。例如,如果我将<code>add3</code>定义为<code>yield</code>三个<code>Get()</code>,然后<code>yield</code>它们的结果之和,我可以</p>
<pre><code>print [x for x in withGen(withSelector(isOdd, add3()), withGen(withSelector(isEven, pair()), arr.__iter__()))]
#prints [(2, 4), 9, (6, 8), 27, (10, 12), (14, 16), 45]
</code></pre>