【问题标题】:Avoid or delay evaluation of things which may not be used避免或延迟评估可能不会使用的东西
【发布时间】:2012-03-21 10:45:41
【问题描述】:

如何在 Python 中实现惰性求值?几个简单的例子:

>>> def foo(x):
...     print(x)
...     return x
... 
>>> random.choice((foo('spam'), foo('eggs')))
spam
eggs
'eggs'

在上面,我们实际上并不需要评估这个元组的所有项目来选择一个。在下面,除非字典中实际上缺少查找键,否则不需要计算默认的foo()

>>> d = {1: "one"}
>>> d.get(2, foo("default"))
default
'default'
>>> d.get(1, foo("default"))
default
'one'

我正在寻找一种 Pythonic 方式来重构上述示例以进行惰性评估。

【问题讨论】:

  • 是的,您所描述的通常称为惰性评估。
  • 这里显而易见的答案就是在做出选择后应用foo() 函数。此外,当您使用迭代器时,请记住在列表上使用生成器进行惰性求值。

标签: python lazy-evaluation


【解决方案1】:

在 Python 中进行惰性求值的标准方法是使用 generators

def foo(x):
    print x
    yield x

random.choice((foo('spam'), foo('eggs'))).next()

顺便说一句。 Python 也允许generator expressions,所以下面的行不会预先计算任何东西:

g = (10**x for x in xrange(100000000))

【讨论】:

  • 这将创建一堆生成器,然后只使用其中一个,丢弃其余的。使用 lambdas 的速度是原来的两倍,因为它们的开销更少:next(random.choice(tuple(foo(q) for q in range(10000000)))) → 21s(当然没有打印),random.choice(tuple(lambda q=q: q+1 for q in range(10000000)))() → 10s。所以OP提出的“丑”版本是最好的解决方案。
【解决方案2】:

可以使用partial(-ly应用函数):

import random
def foo(x):
    print x
    return x

from functools import partial
print random.choice((partial(foo,'spam'), partial(foo,'eggs')))()

当您需要具有默认值的 dict 时,您可以使用 defaultdict

from collections import defaultdict
d = defaultdict(somedefault)
print d[k] # calls somedefault() when the key is missing

Python 不是一种惰性语言,并且没有对惰性的特殊支持。当您想稍后生成一个单独的值时,您必须将它包装在一个函数中。此外,generators 可用于稍后生成一系列值。

【讨论】:

    【解决方案3】:

    除非你给出一个更现实的例子,否则我会这样做:

    >>> def foo(x):
    ...     print x
    ...     return x
    ...
    >>> foo(random.choice(("spam", "eggs")))
    spam
    'spam'
    

    但是你可以像这样创建一个辅助类:

    class LazyEval(object):
        def __init__(self, func, *args, **kwargs):
            self.func = func
            self.args = args
            self.kwargs = kwargs
    
        def __call__(self):
            return self.func(*self.args, **self.kwargs)
    
    random.choice((LazyEval(foo, "spam"), LazyEval(foo, "eggs")))()
    

    【讨论】:

      【解决方案4】:

      另一种解决方案是构建并返回一个可调用对象,该可调用对象封装了您要对随机选择执行的操作。

      def foo(sequence):
          def chooser():
              choice = random.choice(sequence)
              print choice
              return choice
          return chooser
      
      >>> c = foo(['spam', 'eggs', 'ham'])
      >>> c()
      ... ham
      >>> 'ham'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-13
        • 2021-05-17
        • 1970-01-01
        • 2021-12-18
        • 2011-03-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多