pythonmemoization

Caching class attributes in Python


I'm writing a class in python and I have an attribute that will take a relatively long time to compute, so I only want to do it once. Also, it will not be needed by every instance of the class, so I don't want to do it by default in __init__.

I'm new to Python, but not to programming. I can come up with a way to do this pretty easily, but I've found over and over again that the 'Pythonic' way of doing something is often much simpler than what I come up with using my experience in other languages.

Is there a 'right' way to do this in Python?


Solution

  • 3.8 ≤ Python @property and @functools.lru_cache have been combined into @cached_property.

    import functools
    class MyClass:
        @functools.cached_property
        def foo(self):
            print("long calculation here")
            return 21 * 2
    

    3.2 ≤ Python < 3.8

    You should use both @property and @functools.lru_cache decorators:

    import functools
    class MyClass:
        @property
        @functools.lru_cache()
        def foo(self):
            print("long calculation here")
            return 21 * 2
    

    This answer has more detailed examples and also mentions a backport for previous Python versions.

    Python < 3.2

    The Python wiki has a cached property decorator (MIT licensed) that can be used like this:

    import random
    # the class containing the property must be a new-style class
    class MyClass(object):
       # create property whose value is cached for ten minutes
       @cached_property(ttl=600)
       def randint(self):
           # will only be evaluated every 10 min. at maximum.
           return random.randint(0, 100)
    

    Or any implementation mentioned in the others answers that fits your needs.
    Or the above mentioned backport.