Ammar Yasser
Ammar Yasser

Reputation: 33

Do decorators consume more memory?

On a Corey Schafer tutorial, he wrote the following code to measure the amount of memory a specific function has consumed.

import time
import random
import memory_profiler

names = ['john', 'Corey', 'Adam', 'Steve', 'Rick', 'Thomas']
majors = ['Math', 'Engineering', 'CompSci', 'Art', 'Business']
print('Memory (before): {}Mb'.format(memory_profiler.memory_usage()))

def people_list(num_of_people):
    result = []
    for i in range(num_of_people):
        person = {'id': i, 
                  'name' : random.choice(names),
                  'major' : random.choice(majors)}
        result.append(person)
    return result

t1 = time.process_time()
people_list(1000000)
t2 = time.process_time()
print('Memory (After): {}Mb'.format(memory_profiler.memory_usage()))
print('Took {} seconds'.format(t2-t1))

The results were

Memory (before): [34.21875]Mb
Memory (After): [34.47265625]Mb
Took 2.390625 seconds

but when I tried to create a decorator to add the memory and time measuring functionality to my function, the difference in memory before and after the function execution was huge. This is my code

import time
import random
import memory_profiler

names = ['john', 'Corey', 'Adam', 'Steve', 'Rick', 'Thomas']
majors = ['Math', 'Engineering', 'CompSci', 'Art', 'Business']

def decorator(original_func):
    def wrapper(*args, **kwargs):
        before_memory = memory_profiler.memory_usage()
        print('Memory (before): {} Mbs'.format(before_memory))
        t1 = time.time()
        output = original_func(*args, **kwargs)
        t2 = time.time()
        time_diff = t2 - t1
        after_memory = memory_profiler.memory_usage()
        print("Memory (after): {} Mbs".format(after_memory))
        print('{} ran in {} seonds'.format(original_func.__name__, time_diff))
        return output
    return wrapper

@decorator
def people_list(num):
    result = []
    for i in range(num):
        person = {'id' : i+1, 
                  'name' : random.choice(names), 
                  'major' : random.choice(majors)}
        result.append(person)
    return result

people_list(1000000)

and the results were

Memory (before): [47.07421875] Mbs
Memory (after): [319.875] Mbs
people_list ran in 2.5296807289123535 seonds

Upvotes: 3

Views: 544

Answers (1)

Daniel
Daniel

Reputation: 42758

Without decorator you discard the result of your function call at once. In the decorator example, the result is kept in output, when looking at memory usage.

Try the first example with:

t1 = time.process_time()
output = people_list(1000000)
t2 = time.process_time()
print('Memory (After): {}Mb'.format(memory_profiler.memory_usage()))
print('Took {} seconds'.format(t2-t1))

and you should get the same memory usage.

Upvotes: 6

Related Questions