我想出了两种方法来实现这样的基本版本,每种方法都有自己的局限性。这是第一个版本:
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()
您可以像这样使用它(基于 Mathematica 文档页面中的一个示例):
>>> @sower
... def someSum():
... return sum(sow(x**2 + 1) if (x**2 + 1) % 2 == 0 else x**2 + 1 for x in xrange(1, 11))
>>> someSum()
395
>>> reap(someSum())
(395, [2, 10, 26, 50, 82])
这有许多限制:
- 任何想要使用的功能都必须使用
sow
装饰器进行sower
装饰。这意味着您不能sow
像 Mathematica 示例那样使用内部内联表达式,如列表推导式。您可能可以通过检查调用堆栈来破解它,但它可能会变得丑陋。
- 任何播种但未收获的价值都会永远存储在“农场”中,因此随着时间的推移,农场会变得越来越大。
- 它没有文档中显示的“标签”功能,尽管添加起来并不难。
写这篇文章让我想到了一个更简单的实现,但权衡略有不同:
farm = []
def sow(val):
if farm:
farm[-1].append(val)
return val
def reap(expr):
farm.append([])
val = expr()
return val, farm.pop()
这个你可以像这样使用,它有点类似于 Mathematica 版本:
>>> 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])
这个不需要装饰器,它会清理收割的值,但它需要一个无参数函数作为它的参数,这需要你将播种表达式包装在一个函数中(这里用 完成lambda
)。此外,这意味着被 reaped 表达式调用的任何函数中的所有播种值都将插入到同一个列表中,这可能会导致奇怪的排序;我无法从 Mathematica 文档中看出这是 Mathematica 所做的还是什么。