Avoid or delay evaluation of things which may not be used

不想你离开。 提交于 2019-12-19 07:28:09

问题


How can lazy evaluation be achieved in Python? A couple of simple examples:

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

Above, we didn't really need to evaluate all the items of this tuple, in order to choose one. And below, the default foo() didn't really need to be computed unless the lookup key was actually missing from the dict:

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

I'm looking for a Pythonic way to refactor examples like the above to evaluate lazily.


回答1:


The standard way of doing lazy evaluation in Python is using generators.

def foo(x):
    print x
    yield x

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

BTW. Python also allows generator expressions, so below line will not pre-calculate anything:

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



回答2:


You can use apartial(-ly applied function):

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

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

When you need a dict with defaults you can use a defaultdict

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

Python is not a lazy language and there is no special support for laziness. When you want to generate a individual value later, you must wrap it in a function. In addition, generators can be used to generate a sequence of values at a later time.




回答3:


Unless you give use a more realistic example, I would do it like this:

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

But you could create a helper class like this:

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:


Another solution is to build and return a callable that encapsulates the actions you want to perform on the random selection.

def foo(sequence):
    def chooser():
        choice = random.choice(sequence)
        print choice
        return choice
    return chooser

>>> c = foo(['spam', 'eggs', 'ham'])
>>> c()
... ham
>>> 'ham'


来源:https://stackoverflow.com/questions/9802981/avoid-or-delay-evaluation-of-things-which-may-not-be-used

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!