Imagine you could make your Python programs run much faster without much effort. That’s what caching can do for you. Think of python caching as a way to save the answers to hard problems so you don’t have to solve them again. By keeping these answers handy, your programs can skip the hard work and get results quickly.
When you use pcaching, you store the results of time-consuming calculations. The next time your program needs that result, it can just grab it from storage instead of doing the calculation all over again. This not only speeds up your code but also makes it easier to handle complex tasks.
In this article, we will learn how to use this powerful technique to turbocharge your code and achieve smoother, faster Python experiences.
Caching involves saving the results of expensive or frequently executed operations so that subsequent calls with the same parameters can return the cached results instead of recomputing them. This reduces the time complexity, especially for functions with high computational costs or those that are called repeatedly with the same inputs.
Caching is beneficial in scenarios where:
Python’s functools module provides a built-in caching decorator called lru_cache, which stands for Least Recently Used cache. It’s easy to use and highly effective for many use cases.
Here’s how you can use lru_cache to cache function results:
from functools import lru_cache
You apply lru_cache to a function to cache its return values.
@lru_cache(maxsize=128)
def expensive_function(x):
# Simulate an expensive computation
result = x * x
return result
maxsize specifies the number of results to cache. Once this limit is reached, the least recently used result is discarded. Setting maxsize=None allows the cache to grow indefinitely.
import time
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
start_time = time.time()
print(fibonacci(35)) # First call will take longer
print("First call took", time.time() - start_time, "seconds")
start_time = time.time()
print(fibonacci(35)) # Subsequent calls are much faster
print("Second call took", time.time() - start_time, "seconds")
For more complex scenarios, you might need custom caching solutions. Python offers various libraries and techniques for creating custom caches:
cache = {}
def expensive_function(x):
if x not in cache:
cache[x] = x * x # Simulate an expensive computation
return cache[x]
The cachetools library provides a variety of cache types and is more flexible than lru_cache.
from cachetools import cached, LRUCache
cache = LRUCache(maxsize=128)
@cached(cache)
def expensive_function(x):
return x * x # Simulate an expensive computation
query_cache = {}
def get_user_data(user_id):
if user_id not in query_cache:
# Simulate a database query
query_cache[user_id] = {"name": "John Doe", "age": 30}
return query_cache[user_id]
import requests
api_cache = {}
def get_weather(city):
if city not in api_cache:
response = requests.get(f'http://api.weather.com/{city}')
api_cache[city] = response.json()
return api_cache[city]
Caching is a mechanism to optimise python code, especially when it comes to expensive computations and function calls which are not recurring. We can use this to build our cache easily using tools already available in Python itself like functools.lry_cache or other custom ways to cache, huge performance wins of the application can be attained. Cache is an effective tool to save time and resources, whether you are optimizing database queries or API calls (as we will in this example), computational functions etc.
A. It stores the results of expensive function calls and reuses them for the same inputs to improve performance.
A. Use caching for functions with expensive computations, frequent calls with the same arguments, and immutable, deterministic results.
A. Caching is useful for optimizing database queries and API calls, reducing load and improving response times.