How do I cache method calls in Python?


The two tools for caching methods are functools.cached_property() and functools.lru_cache(). Both the module is part of the functools module. The functools module is for higher-order functions: functions that act on or return other functions. Let us first install and import the functools module −

Install functools

To install the functools module, use the pip −

pip install functools

Import functools

To import functools −

import functools

Let us understand both the caching one by one −

cached_property()

useful for expensive computed properties of instances that are otherwise effectively immutable.

The cached_property approach only works with methods that do not take any arguments. It does not create a reference to the instance. The cached method result will be kept only as long as the instance is alive.

The advantage is that when an instance is no longer used, the cached method result will be released right away. The disadvantage is that if instances accumulate, so too will the accumulated method results. They can grow without bound.

Example

Let us see an example −

class DataSet: def __init__(self, sequence_of_numbers): self._data = tuple(sequence_of_numbers) @cached_property def stdev(self): return statistics.stdev(self._data)

lru_cache

The lru_cache approach works with methods that have hashable arguments. It creates a reference to the instance unless special efforts are made to pass in weak references.

The advantage of the least recently used algorithm is that the cache is bounded by the specified maxsize. The disadvantage is that instances are kept alive until they age out of the cache or until the cache is cleared.

Example

Let us see an example −

@lru_cache def count_vowels(sentence): return sum(sentence.count(vowel) for vowel in 'AEIOUaeiou')

An example of computing Fibonacci using a cache −

from functools import lru_cache @lru_cache(maxsize=None) def fib(n): if n < 2: return n return fib(n-1) + fib(n-2) print([fib(n) for n in range(16)]) print(fib.cache_info())

Output

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)

Caching Example

Now, let us see a complete example of both the functool cached_property() and lru_cache −

from functools import lru_cache from functools import cached_property class Weather: "Lookup weather information on a government website" def __init__(self, station_id): self._station_id = station_id # The _station_id is private and immutable def current_temperature(self): "Latest hourly observation" # Do not cache this because old results # can be out of date. @cached_property def location(self): "Return the longitude/latitude coordinates of the station" # Result only depends on the station_id @lru_cache(maxsize=20) def historic_rainfall(self, date, units='mm'): "Rainfall on a given date" # Depends on the station_id, date, and units.

Updated on: 19-Sep-2022

2K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements