Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save farhad0085/5586ac45e37c0a8bfb39cb6199ccd20b to your computer and use it in GitHub Desktop.

Select an option

Save farhad0085/5586ac45e37c0a8bfb39cb6199ccd20b to your computer and use it in GitHub Desktop.
Python Decorator for Function Result Caching

Python Decorator for Function Result Caching

# Import necessary modules
import time
import hashlib

# Function to add any number of arguments and simulate a long computation time
def add(*x):
    time.sleep(5)  # Simulate a delay of 5 seconds (Long computation time)
    return sum(i for i in x)

# Decorator function to memorize the results of a function using a cache
def memorize(func):
    cache = {}  # Initialize an empty cache dictionary

    def original_function(*args, **kwargs):
        # Convert the arguments and keyword arguments to an MD5 hash to decrease memory load
        key = hashlib.md5((str(args) + str(kwargs)).encode()).hexdigest()
        print(cache)

        if cache.get(key):  # Check if the result is already in the cache
            print("taking the result from cache")
            return cache[key]  # Return the cached result
        else:
            print("calculating the result")
            result = func(*args, **kwargs)  # Call the original function to calculate the result
            cache[key] = result  # Store the result in the cache
            return result  # Return the calculated result
    
    return original_function  # Return the inner function

# Apply the 'memorize' decorator to the 'add' function
summer = memorize(add)

# Generate a range of numbers from 1 to 499999
numbers = range(1, 500000)

start = time.time()
print(summer(*numbers))
end = time.time()
print("time took", end - start)

start = time.time()
print(summer(*numbers))
end = time.time()
print("time took", end - start)

start = time.time()
print(summer(*numbers))
end = time.time()
print("time took", end - start)

Usage:

Scenario: Optimizing Computation in a Web App with Result Caching

In a web application, there is a computation that involves processing a significant amount of data. The computation takes a considerable amount of time for each request. However, when the same input data is provided, the output of the computation is deterministic and remains the same for subsequent requests. In such cases, it is more efficient to cache the results of previous computations and return the cached value instead of reprocessing the same data repeatedly.

To achieve this, we can implement a caching mechanism using a decorator. The decorator will memorize the results of the computation for specific input data and store them in a cache. Subsequent requests with the same input data will fetch the result from the cache, eliminating the need for redundant processing.

Following example explains it better.

from flask import Flask, request, jsonify
import time
import hashlib

app = Flask(__name__)

# Function to add any number of arguments and simulate a long computation time
def add(*x):
    time.sleep(5)  # Simulate a delay of 5 seconds (Long computation time)
    return sum(i for i in x)

# Decorator function to memorize the results of a function using a cache
def memorize(func):
    cache = {}  # Initialize an empty cache dictionary

    def original_function(*args, **kwargs):
        # Convert the arguments and keyword arguments to an MD5 hash to decrease memory load
        key = hashlib.md5((str(args) + str(kwargs)).encode()).hexdigest()

        if cache.get(key):  # Check if the result is already in the cache
            return cache[key]  # Return the cached result
        else:
            result = func(*args, **kwargs)  # Call the original function to calculate the result
            cache[key] = result  # Store the result in the cache
            return result  # Return the calculated result
    
    return original_function  # Return the inner function

# Apply the 'memorize' decorator to the 'add' function
add = memorize(add)

@app.route('/calculate', methods=['POST'])
def calculate():
    try:
        # Parse the JSON payload from the request
        data = request.get_json()

        # Extract the necessary parameters from the JSON payload
        numbers = data['numbers']

        # Call the 'add' function with the extracted data
        result = add(*numbers)

        # Return the result as a JSON response
        return jsonify({'result': result})

    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True)

Limitation:

  • The caching mechanism implemented by the memorize decorator assumes that the function's output is solely dependent on its inputs and does not take into account any external factors, such as the current time.
  • If a function's result depends on external factors like the current time, random numbers, or any other non-deterministic input, caching may not work as expected, and the function may need to be recomputed each time it is called.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment