Использование памяти объектами Python

Опубликован: 26.10.2023 115

В Python данные хранятся в памяти в виде объектов.

Каждый объект представляет собой комбинацию самих значений данных и метаданных, таких как тип объекта и ссылки на другие объекты.

Каждая переменная является ссылкой на объект в памяти, что позволяет работать с данными эффективно и гибко.

Все объекты в Python с точки зрения использования памяти можно разделить на:

  • плоские (например, str, int, float, bytes, array.array);
  • контейнерные (например, list, tuple, set, dict).

В памяти, занятой плоскими объектами, хранятся сами значения этих объектов, тогда как в контейнерных объектах хранятся только ссылки на объекты любого типа (плоские или контейнерные). Так например, списки - это массивы ссылок на Python-объекты, что позволяет хранить в них объекты различных типов.

Поэтому плоские объекты компактнее (занимают меньше памяти), но могут содержать только значения примитивных машинных типов, например байты, целые числа и числа с плавающей точкой.

В Python проверить использование памяти объектом можно с помощью функции sys.getsizeof() модуля sys, которая возвращает размер объекта в байтах:

import sys

# целое число  (int) занимает 28 байт
sys.getsizeof(3)
28
sys.getsizeof(123456789)  #  целое 9-значное число занимает тоже 28 байт
28
sys.getsizeof(1234567891)  # целое 10-значное число занимает уже на 4 байта больше
32

# число с плавающей точкой float занимает 24 байта
sys.getsizeof(7.2)
24
sys.getsizeof(123456789.123456789)  # float с 9-значным числом занимает тоже 24 байта
24

# пустая строка str занимает 49 байт
sys.getsizeof('')
49

# строка из одного символа '1' всего 50 байт
sys.getsizeof('1')
50

# строка из 5-ти символов занимает 54 байта (+ по одному байту на символ)
sys.getsizeof('12345')
54
sys.getsizeof("Эта очень длинная строка занимает всего 188 байт памяти !")
188

Таким образом, мы видим, что простое и 9-ти значное целое число int занимают одинаковый размер памяти (28 байт), а начиная с 10-ти значного целого числа добавляется еще 4 байта (до 32 байт). Число с плавающей точкой float занимает всего 24 байта независимо от значения числа и количества десятичных знаков. Пустая строка занимает 49 байтов, а каждый символ строки добавляет еще один байт.

Все дело в том, что у объектов Python огромные фиксированные накладные расходы памяти.

# 
my_list = [x for x in range(0, 10000)]
my_tuple =  (x for x in range(0, 10000))
my_set = set(my_list)

print(sys.getsizeof(my_list))
85176
print(sys.getsizeof(my_tuple))
200
print(sys.getsizeof(my_set))
524504

Приведенный пример показывает, что большой список list из 10000 элементов занимает 85176 байт памяти.

В отличие от списка кортеж tuple из такого же количества элементов занимает всего 200 байт (или в 425 раз меньше).

А множество set, созданное из того же списка, требует в 6.15 раз больше памяти. Это результат использования множеством хеш-таблицы, которая хранится в памяти и позволяет производить над множествами вычисления гораздо быстрее, чем аналогичные операции со списками.

В Python наиболее экономное использование памяти обеспечивают объекты-генераторы (такие, как например функция range()):

import sys

my_list = range(0, 10000)
print(sys.getsizeof(my_list))
48

Похожие посты

Оценка основных статистических метрик набора данных в Python

Область эффективного использования lambda функции в Python

Логические выражения if ... else в Pythonic стиле

Способы удаления лишних пробелов в строке

Комментариев нет.