Трудно укусить python диктовать для сохранения значений ключом.
Библиотека классов записей может помочь уменьшить объем памяти следующим образом.
from recordclass import make_arrayclass, litelist
from random import randint
Модуль tracemalloc
используется для оценки объема памяти:
import tracemalloc
class Tracer:
def __enter__(self):
if tracemalloc.is_tracing():
raise ValueError('nesting tracemalloc is not allowed')
self.allocated = None
tracemalloc.start()
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
self.allocated = current
Сначала оценим «вес» части дикта:
with Tracer() as t0:
d0 = {i:None for i in range(5_000_000)}
print("dict:", t0.allocated // 1_000_000, 'Mb')
del d0, t0
Результат - 307 Мб
Во-вторых, давайте оценим объем памяти словаря с 5_000_000 записей. Ключ представляет собой тройку случайных целых чисел, значение представляет собой список из 6 случайных целых чисел.
with Tracer() as t1:
d1 = {}
for i in range(N):
key = (randint(0,N), randint(0,N), randint(0,N))
val = [randint(0,N) for i in range(10)]
d1[key] = val
print("regular:", t1.allocated // 1_000_000, 'Mb')
del d1, t1
Результат составляет 3387 Мб. Таким образом, часть диктата относительно мала.
Чтобы уменьшить объем памяти кортежей и списков, можно использовать make_arrayclass
и litelist
из библиотеки recordclass
:
Triple = make_arrayclass("Triple", 3, hashable=True)
with Tracer() as t2:
d2 = {}
for i in range(N):
key = Triple(randint(0,N), randint(0,N), randint(0,N))
val = litelist([randint(0,N) for i in range(6)])
d2[key] = val
print("recordclass:", t2.allocated // 1_000_000, 'Mb')
del d2, t2
Результат - 2107 Мб. Таким образом, это экономит около 1 Гб.
PS: используется Python 3.7.