I was actually kind of bored and since I'm studying some Python data structures I decided to make some size(MB) and time(secs) comparisons between different containers when conducting the operation of adding n items to each container type. I included:
- List appending
- List initialization
- List comprehensions
- Array
- Set comprehensions
- Generator comprehensions
- Dictionary comprehensions
- Tuple
- Set add
- Dictionary assignment
I hope you enjoy using it, since it's mainly for fun purposes and might give you some insight on efficiency.
from time import time
from array import array
import sys
import operator
class MakeContainers:
"""Produce containers of different types."""
def __init__(self, n):
self.size = n
def get_appends(self):
"""Return time and size for appending a list."""
start_time = time()
sequence = []
for i in range(self.size):
sequence.append(i)
return time() - start_time, sys.getsizeof(sequence)
def get_initialization(self):
"""Return time and size for list initialization."""
start_time = time()
sequence = [None] * self.size
for i in range(self.size - 1):
sequence[i] = i
return time() - start_time, sys.getsizeof(sequence)
def get_list_comprehensions(self):
"""Return time and size for list comprehensions."""
start_time = time()
sequence = [x for x in range(self.size)]
return time() - start_time, sys.getsizeof(sequence)
def get_array(self):
"""Return array time and size."""
start_time = time()
sequence = array('i', [x for x in range(self.size)])
return time() - start_time, sys.getsizeof(sequence)
def get_generator_comprehensions(self):
"""Return generator comprehensions time and size."""
start_time = time()
sequence = (x for x in range(self.size))
return time() - start_time, sys.getsizeof(sequence)
def get_set_comprehensions(self):
"""Return set comprehensions time and size."""
start_time = time()
sequence = {x for x in range(self.size)}
return time() - start_time, sys.getsizeof(sequence)
def get_dictionary_comprehensions(self):
"""Return dictionary comprehensions time and size."""
start_time = time()
sequence = {x: x for x in range(self.size)}
return time() - start_time, sys.getsizeof(sequence)
def get_tuple(self):
"""Return time and size of making a tuple."""
start_time = time()
sequence = tuple(x for x in range(self.size))
return time() - start_time, sys.getsizeof(sequence)
def get_set_add(self):
"""Return time and size of adding items to a set."""
start_time = time()
sequence = set()
for i in range(self.size):
sequence.add(i)
return time() - start_time, sys.getsizeof(sequence)
def get_dictionary_assignment(self):
"""Return time and size of assigning values to a dictionary."""
start_time = time()
sequence = {}
for i in range(self.size):
sequence[i] = i
return time() - start_time, sys.getsizeof(sequence)
def test_containers(n):
"""Test containers of different types and print results for size n."""
test = MakeContainers(n)
size_rank = time_rank = 1
operation_index = 0
sizes = {}
times = {}
operations = [
'List appends', 'List initializations', 'List comprehensions', 'Array', 'Generator comprehensions',
'Set comprehensions', 'Dictionary comprehensions', 'Tuple', 'Set add', 'Dictionary assignment'
]
values = [
test.get_appends(), test.get_initialization(), test.get_list_comprehensions(), test.get_array(),
test.get_generator_comprehensions(), test.get_set_comprehensions(), test.get_dictionary_comprehensions(),
test.get_tuple(), test.get_set_add(), test.get_dictionary_assignment()
]
for value in values:
times[operations[operation_index]] = value[0]
sizes[operations[operation_index]] = value[1]
operation_index += 1
print('Size ranks:')
print(35 * '=')
for operation, size in sorted(sizes.items(), key=operator.itemgetter(1)):
print(f'Rank: {size_rank}')
print(f'Operation: {operation}\nSize: {size / 10 ** 6} MB.')
print(f'Number of items: {n}')
size_rank += 1
print(35 * '=')
print()
print('Time ranks:')
print(35 * '=')
for operation, timing in sorted(times.items(), key=operator.itemgetter(1)):
print(f'Rank: {time_rank}')
print(f'Operation: {operation}\nTime: {timing} seconds.')
print(f'Number of items: {n}')
time_rank += 1
print(35 * '=')
if __name__ == '__main__':
st_time = time()
test_containers(10 ** 7)
print(f'Total time: {time() - st_time} seconds.')
get_generator_comprehensions()
creates a generator that is never iterated over. It is like saying "get ready to count to 10 million. You ready? Great! How much time has that taken you?" You haven't done any counting yet. #2)sys.getsizeof()
returns the size of the container, but not (necessarily) the contents, because the contents are (usually) references to other objects, so may not be "owned" by the container.array.array()
is an exception. It directly contains the values it stores. Memory wise, it looks 2x better than a list, but is actually 9x better! \$\endgroup\$