据我所知,发电机是懒惰的,但也不是很懒惰。无论何时使用生成器,在使用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是否有这样的东西。
答案 0 :(得分:1)
我发现(在谷歌中)很多关于Python中懒惰评估的文章,并且通常大多数人都说使用lambdas和生成器就像你一样,并且#34;足够好"但不是完美的方法。我还发现至少有两个试图实现延迟评估的模块:lazypy和lazy_python。
我认为第二个可能是好的,因为它允许使用@lazy_function
装饰器强制解释器创建所谓的thunks
并在您真正需要时对其进行评估。但是我没有测试这个模块,我注意到它有几个已知的错误和限制。