懒惰评估收益率值

时间:2015-11-13 12:57:58

标签: python-3.x lazy-evaluation

据我所知,发电机是懒惰的,但也不是很懒惰。无论何时使用生成器,在使用next时都会计算yielding表达式,尽管此时仅对其进行求值。

在查找'长度'的特定用例中。生成器sum(1 for _ in generator)或仅使用某些元素[x for idx, x in enumerate(generator) if i%2==1]时,这是一种耻辱。

我想知道是否有一种透明的方式来返回或产生对象作为在使用(未调用)时自动评估的表达式:就像在Haskell中一样。

将此示例视为一项昂贵的功能:

## Some expensive 'constructor'/'creator' for objects

def create_object(x):
    print('expensive computation')
    return 2*x

天真地,这将是在生成器中使用它时的一般approch:

## Naive approach:
print("NAIVE")
def special_objects(n, parity):
    for i in range(n):
        if i % 2 == parity:
            yield create_object(i)

尽管发电机价格昂贵,但它也很直观且易于使用:

# Is expensive, as every yielded expression is evaluated:           
print( sum(1 for _ in special_objects(5, 1)) )

# but also is 'transparent', you don't have to explicitely evaluate each element
# (except looping through the elements, but this is the generator's lazy
# evaluation, not that of the object's evaluation itself.
print(list(special_objects(5, 1)))

然而,另一种选择不太直观,但也更便宜:

## A factory approach
print("FACTORY")

def special_object_factories(n, parity):
    for i in range(n):
        if i % 2 == parity:
            yield lambda: create_object(i)

# Is efficient, as none of the objects are created at all:
print( sum(1 for _ in special_object_factories(5, 1)) )

# But it is not transparent, you have to evaluate the objects yourself and cache
# the values if you need them multiple times.
print([o() for o in special_object_factories(5, 1)])

是否有一种透明的方式来返回或产生被评估为懒惰的表达式(即不使用lambda'你需要手动缓存和评估,而不是有警告的东西)?

在C ++ 14中,您可以编写各种花哨的包装类来实现这一点,这只会真正成为'他们被解除引用的东西'或者'使用'在某种程度上,我想知道Python 3是否有这样的东西。

1 个答案:

答案 0 :(得分:1)

我发现(在谷歌中)很多关于Python中懒惰评估的文章,并且通常大多数人都说使用lambdas和生成器就像你一样,并且#34;足够好"但不是完美的方法。我还发现至少有两个试图实现延迟评估的模块:lazypylazy_python

我认为第二个可能是好的,因为它允许使用@lazy_function装饰器强制解释器创建所谓的thunks并在您真正需要时对其进行评估。但是我没有测试这个模块,我注意到它有几个已知的错误和限制。