Python equivalent of Scala's lazy val

python, scala

Solution

In Scala, `lazy val` is a final variable that is evaluated once at the time it is first accessed, rather than at the time it is declared. It is essentially a memoized function with no arguments. Here's one way you can implement a memoization decorator in Python:

from functools import wraps

def memoize(f):
    @wraps(f)
    def memoized(*args, **kwargs):
        key = (args, tuple(sorted(kwargs.items()))) # make args hashable
        result = memoized._cache.get(key, None)
        if result is None:
            result = f(*args, **kwargs)
            memoized._cache[key] = result
        return result
    memoized._cache = {}
    return memoized

Here's how it can be used. With `property` you can even drop the empty parentheses, just like Scala:

>>> class Foo:
...     @property
...     @memoize
...     def my_lazy_val(self):
...         print "calculating"
...         return "some expensive value"

>>> a = Foo()
>>> a.my_lazy_val
calculating
'some expensive value'

>>> a.my_lazy_val
'some expensive value'

Problem

I'm currently trying to port some Scala code to a Python project and I came across the following bit of Scala code: ``` lazy val numNonZero = weights.filter { case (k,w) => w > 0 }.keys ``` `weights` is a really long list of tuples of items and their associated probability weighting. Elements are frequently added and removed from this list but checking how many elements have a non-zero probability is relatively rare. There are a few other rare-but-expensive operations like this in the code I'm porting that seem to benefit greatly from usage of `lazy val`. What is the most idiomatic Python way to do something similar to Scala's `lazy val`?

Original source