Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid or delay evaluation of things which may not be used

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.

like image 409
wim Avatar asked Mar 21 '12 10:03

wim


3 Answers

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))
like image 57
vartec Avatar answered Nov 10 '22 00:11

vartec


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.

like image 38
Jochen Ritzel Avatar answered Nov 10 '22 01:11

Jochen Ritzel


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")))()
like image 1
orlp Avatar answered Nov 09 '22 23:11

orlp