Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python functional evaluation efficiency

Tags:

python

If I do this:

x=[(t,some_very_complex_computation(y)) for t in z]

Apparently some_very_complex_computation(y) is not dependent on t. So it should be evaluated only once. Is there any way to make Python aware of this, so it won't evaluate some_very_complex_computation(y) for every iteration?

Edit: I really want to do that in one line...

like image 933
aaronqli Avatar asked Dec 03 '22 04:12

aaronqli


2 Answers

Usually you should follow San4ez's advise and just use a temporary variable here. I will still present a few techniques that might prove useful under certain circumstances:

In general, if you want to bind a name just for a sub-expression (which is usually why you need a temporary variable), you can use a lambda:

x = (lambda result=some_very_complex_computation(y): [(t, result) for t in z])()

In this particular case, the following is a quite clean and readable solution:

x = zip(z, itertools.repeat(some_very_complex_computation(y)))

A general note about automatic optimizations like these

In a dynamic language like Python, an implementation would have a very hard time to figure out that some_very_complex_computation is referentially transparent, that is, that it will always return the same result for the same arguments. You might want to look into a functional language like Haskell if you want magic like that.

"Explicit" pureness: Memoization

What you can do however is make some_very_complex_computation explicitly cache its return values for recent arguments:

from functools import lru_cache

@lru_cache()
def some_very_complex_computation(y):
  # ...

This is Python 3. In Python 2, you'd have to write the decorator yourself:

from functools import wraps

def memoize(f):
  cache = {}
  @wraps(f)
  def memoized(*args):
    if args in cache:
      return cache[args]
    res = cache[args] = f(*args)
    return res
  return memoized

@memoize
some_very_complex_computation(x):
  # ...
like image 111
Niklas B. Avatar answered Dec 05 '22 18:12

Niklas B.


No, you should save value in variable

result = some_very_complex_computation(y)
x = [(t, result) for t in z]
like image 22
San4ez Avatar answered Dec 05 '22 17:12

San4ez