<p>我想出了两种方法来实现这种东西的基本版本,每种方法都有自己的局限性。以下是第一版:</p>
<pre><code>farm = []
def sower(func):
def wrapped(*args, **kw):
farm.append([])
return func(*args, **kw)
return wrapped
def sow(val):
farm[-1].append(val)
return val
def reap(val):
return val, farm.pop()
</code></pre>
<p>您可以这样使用它(基于Mathematica doc页面中的一个示例):</p>
^{pr2}$
<p>这有许多限制:</p>
<ol>
<li>任何要使用<code>sow</code>的函数都必须用<code>sower</code>修饰符修饰。这意味着您不能像Mathematica示例那样在内联表达式(如列表理解)中使用<code>sow</code>。您可以通过检查调用堆栈来破解这个问题,但它可能会变得很难看。在</li>
<li>任何被播种但没有收获的价值都会永远储存在“农场”里,因此农场会随着时间的推移变得越来越大。在</li>
<li>它没有文档中显示的“标记”功能,尽管这并不难添加。在</li>
</ol>
<p>写这篇文章让我想到了一个更简单的实现,它有着稍微不同的权衡:</p>
<pre><code>farm = []
def sow(val):
if farm:
farm[-1].append(val)
return val
def reap(expr):
farm.append([])
val = expr()
return val, farm.pop()
</code></pre>
<p>您可以这样使用这个,它有点类似于Mathematica版本:</p>
<pre><code>>>> reap(lambda: sum(sow(x**2 + 1) if (x**2 + 1) % 2 == 0 else x**2 + 1 for x in xrange(1, 11)))
(395, [2, 10, 26, 50, 82])
</code></pre>
<p>这个函数不需要decorator,它会清除获取的值,但是它使用一个无参数函数作为参数,这需要您将播种表达式包装在一个函数中(这里用<code>lambda</code>完成)。另外,这意味着,被获取的表达式调用的任何函数中的所有播种值都将被插入到同一个列表中,这可能会导致奇怪的排序;我无法从Mathematica文档中判断Mathematica是这样做的还是怎么做的。在</p>