惰性评估屈服值
Lazy evaluation of yield'ed values
据我所知,生成器是懒惰的,但也不是很懒惰。每当您使用生成器时,产生的表达式都会在使用 next 传递它时进行计算,尽管它只在此时进行计算。
在寻找生成器 'length' 的特定用例中 sum(1 for _ in generator)
或仅使用某些元素时 [x for idx, x in enumerate(generator) if i%2==1]
,这是一种耻辱。
我想知道是否有一种透明的方法来 return 或将对象作为表达式生成,这些表达式在使用(未调用)时自动求值:如 Haskell.[=16 中所做的那样=]
将此示例视为一个昂贵的函数:
## Some expensive 'constructor'/'creator' for objects
def create_object(x):
print('expensive computation')
return 2*x
天真地这将是在生成器中使用它时的一般方法:
## 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)])
是否有一种透明的方法来 return 或 yield 惰性计算的表达式(即不使用需要手动缓存和计算的 lambda,而不是有警告的东西)?
在 C++14 中,您可以编写各种精美的包装器 -类 来执行此操作,只有 'become' 如果它们是 'dereferenced' 或 'used' 在某种程度上,我想知道 Python 3.
是否有类似的东西
我在 Python 中(在 google 中)发现了很多关于惰性求值的文章,通常大多数文章都说像您一样使用 lambda 和生成器是 "good enough" 但是不完美的方法。我还发现至少有两个模块试图实现惰性求值:lazypy and lazy_python.
我认为第二个可能不错,因为它允许使用 @lazy_function
装饰器强制解释器创建所谓的 thunks
并在您真正需要它时对其进行评估。但是我没有测试这个模块,我注意到它有几个已知的错误和限制。
据我所知,生成器是懒惰的,但也不是很懒惰。每当您使用生成器时,产生的表达式都会在使用 next 传递它时进行计算,尽管它只在此时进行计算。
在寻找生成器 'length' 的特定用例中 sum(1 for _ in generator)
或仅使用某些元素时 [x for idx, x in enumerate(generator) if i%2==1]
,这是一种耻辱。
我想知道是否有一种透明的方法来 return 或将对象作为表达式生成,这些表达式在使用(未调用)时自动求值:如 Haskell.[=16 中所做的那样=]
将此示例视为一个昂贵的函数:
## Some expensive 'constructor'/'creator' for objects
def create_object(x):
print('expensive computation')
return 2*x
天真地这将是在生成器中使用它时的一般方法:
## 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)])
是否有一种透明的方法来 return 或 yield 惰性计算的表达式(即不使用需要手动缓存和计算的 lambda,而不是有警告的东西)?
在 C++14 中,您可以编写各种精美的包装器 -类 来执行此操作,只有 'become' 如果它们是 'dereferenced' 或 'used' 在某种程度上,我想知道 Python 3.
是否有类似的东西我在 Python 中(在 google 中)发现了很多关于惰性求值的文章,通常大多数文章都说像您一样使用 lambda 和生成器是 "good enough" 但是不完美的方法。我还发现至少有两个模块试图实现惰性求值:lazypy and lazy_python.
我认为第二个可能不错,因为它允许使用 @lazy_function
装饰器强制解释器创建所谓的 thunks
并在您真正需要它时对其进行评估。但是我没有测试这个模块,我注意到它有几个已知的错误和限制。