We use cookies essential for this site to function well. Please click to help us improve its usefulness with additional cookies. Learn about our use of cookies in our Privacy Policy & Cookies Policy.

Show details

What is Python Caching?

Janvi Kumari 19 Jul, 2024
3 min read

Introduction

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.

How to Speed Up Python Code with Caching

Overview

  • Understand the concept and benefits of caching in Python applications.
  • Implement caching using Python’s built-in functools.lru_cache decorator.
  • Create custom caching solutions using dictionaries and external libraries like cachetools.
  • Apply caching techniques to optimize database queries and API calls for improved performance.

What is Caching?

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.

When to Use Caching?

Caching is beneficial in scenarios where:

  • You have functions with expensive computations.
  • Functions are called multiple times with the same arguments.
  • The function results are immutable and deterministic.

Implementing Caching in Python

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.

Using functools.lru_cache

Here’s how you can use lru_cache to cache function results:

Import the Decorator

from functools import lru_cache

Apply the Decorator

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.

Example Usage

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")

Custom Caching Solutions

For more complex scenarios, you might need custom caching solutions. Python offers various libraries and techniques for creating custom caches:

Using a Dictionary

cache = {}
def expensive_function(x):
    if x not in cache:
        cache[x] = x * x  # Simulate an expensive computation
    return cache[x]

Using cachetools

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

Practical Application

  • Database Queries: Caching results of database queries can significantly reduce the load on your database and improve response times.
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]
  • API Calls: Cache the results of API calls to avoid hitting rate limits and reduce latency.
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]

Conclusion

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.

Frequently Asked Questions

Q1. What is caching?

A. It stores the results of expensive function calls and reuses them for the same inputs to improve performance.

Q2. When should I use caching?

A. Use caching for functions with expensive computations, frequent calls with the same arguments, and immutable, deterministic results.

Q3. What are practical applications of caching?

A. Caching is useful for optimizing database queries and API calls, reducing load and improving response times.

Janvi Kumari 19 Jul, 2024

Hi I am Janvi Kumari currently a Data Science Intern at Analytics Vidhya, passionate about leveraging data for insights and innovation. Curious, driven, and eager to learn. If you'd like to connect, feel free to reach out to me on LinkedIn

Responses From Readers

Clear