Python сколько весит переменная

Функция getsizeof() модуля sys в Python.

Функция getsizeof() модуля sys возвращает размер объекта object в байтах. Объект может быть любым типом объекта. Все встроенные объекты будут возвращать правильные результаты, но sys.getsizeof() не должен выполняться для сторонних расширений, поскольку это зависит от реализации.

Учитывается только потребление памяти, непосредственно приписываемое объекту, а не потребление памяти объектами, к которым он относится.

Если задано default , то будет возвращено значение по умолчанию, если объект не предоставляет средства для получения размера. В противном случае будет вызвано исключение TypeError .

Функция getsizeof() вызывает метод объекта __sizeof__ и добавляет дополнительные издержки сборщика мусора, если объектом управляет сборщик мусора.

Вес некоторых типов переменных

При загрузке некоторых стандартных типов генерируется TypeLoadException
Здравствуйте. У меня возникла следующая проблема — при загрузке некоторых стандартных типов вылазит.

Почему нельзя генерировать исключения некоторых типов из своего кода
MSDN говорит следующее: Я не могу понять почему. Кто нибудь знает ответ на этот вопрос?

Как сделать, чтобы шаблонная функция не использовалась для некоторых типов?
Как сделать, чтобы для определённого типа аргумента использовалась обычная функция вместо.

Область видимости некоторых переменных
Доброго времени, форумчане! Подскажите, пожалуйста, по следующей тематике (visual studio 2010.

Сообщение от DavidPts

у переменных нет веса, не благодари!

если речь о размере то это можно сказать только для True и False
True = 28 или 32 байта зависит от того как считать
False = 24 байта
это актуально для 64 битной ОС, питон 3.8

Угадай, почему остальное перечисленное нельзя сказать?

Сообщение от DavidPts

Сообщение от DavidPts

Лучший ответСообщение было отмечено DavidPts как решение

Решение

int — 2-4 байта для разных платформ.
float — 4 байта
char — 1
bool — в теории 1 бит, на практике равен размеру int

Добавлено через 1 минуту
А в питоне реальный занимаемый размер переменных может отличаться от версии к версии. Даже примитивных типов

Смысл некоторых переменных в коде
Это код тетриса попал мне в руки от младшего товарища ма-смотри-я-без-рук, я не совсем его понял, а.

Использование длинных имен переменных увеличивает вес файла с программой?
Использование длинных имен переменных увеличивает вес файла с программой?

Не получается корректно вывести значения некоторых переменных
Здравствуйте. Написал я код для работы с окнами Виндовс и у меня возникла проблема — не могу.

Преобразование типов переменных
Возник небольшой вопрос Конвертировать следующие форматы BIT в FLOAT NVARCHAR в INT DATETIME.

Приведение типов переменных
Здравствуйте. Вопрос от чайника. Хочу настроить тактирование от HSE, включаю HSE. RCC->CR |= .

Преобразование типов переменных
Осуществить преобразование типов переменных явным и неявным способом по следующим схемам: float.

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

image

Меня часто донимали размышление о том, насколько эффективно Python использует память по сравнению с другими языками программирования. Например, сколько памяти нужно, чтобы работать с 1 миллионом целых чисел? А с тем же количеством строк произвольной длины?
Как оказалось, в Python есть возможность получить необходимую информацию прямо из интерактивной консоли, не обращаясь к исходному коду на C (хотя, для верности, мы туда все таки заглянем).
Удовлетворив любопытство, мы залезем внутрь типов данных и узнаем, на что именно расходуется память.

Все примеры были сделаны в CPython версии 2.7.4 на 32 битной машине. В конце приведена таблица для потребности в памяти на 64 битной машине.

Необходимые инструменты
sys.getsizeof и метод __sizeof__()

Первый инструмент, который нам потребуется находится в стандартной библиотеки sys. Цитируем официальную документацию:

sys.getsizeof(объект[, значение_по_умолчанию])

Возвращает размер объекта в байтах.
Если указано значение по умолчанию, то оно вернется, если объект не предоставляет способа получить размер. В противном случае возникнет исключение TypeError.
Getsizeof() вызывает метод объекта __sizeof__ и добавляет размер дополнительной информации, которая хранится для сборщика мусора, если он используется.

Алгоритм работы getsizeof(), переписанной на Python, мог бы выглядеть следующем образом:

Где PyGC_Head — элемент двойного связанного списка, который используется сборщиком мусора для обнаружения кольцевых ссылок. В исходном коде он представлен следующей структурой:

Размер PyGC_Head будет равен 12 байт на 32 битной и 24 байта на 64 битной машине.

Попробуем вызвать getsizeof() в консоли и посмотрим, что получится:

За исключением магии с проверкой флагов, все очень просто.
Как видно из примера, int и float занимают 12 и 16 байт соответственно. Str занимает 21 байт и еще по одному байту на каждый символ содержимого. Пустой кортеж занимает 12 байт, и дополнительно 4 байта на каждый элемент. Для простых типов данных (которые не содержат ссылок на другие объекты, и соответственно, не отслеживаются сборщиком мусора), значение sys.getsizeof равно значению, возвращаемого методом __sizeof__().

id() и ctypes.string_at

Теперь выясним, на что именно расходуется память.
Для этого нужно нам нужны две вещи: во-первых, узнать, где именно хранится объект, а во-вторых, получить прямой доступ на чтение из памяти. Несмотря на то, что Python тщательно оберегает нас от прямого обращения к памяти, это сделать все таки возможно. При этом нужно быть осторожным, так как это может привести к ошибке сегментирования.

Встроенная функция id() возвращает адрес памяти, где храниться начала объекта (сам объект является C структурой)

Чтобы считать данные по адресу памяти нужно воспользоваться функцией string_at из модуля ctypes. Ее официальное описание не очень подробное:

Теперь попробуем считать данные по адресу, который вернул нам id():

Вид шестнадцатеричного кода не очень впечатляет, но мы близки к истине.

Модель Struct

Для того чтобы представить вывод в значения, удобные для восприятия, воспользуемся еще одним модулем. Здесь нам поможет функция unpack() из модуля struct.

struct
Этот модуль производит преобразование между значениями Python и структурами на C, представленными в виде строк.

struct.unpack(формат, строка)
Разбирает строку в соответствие с данным форматов. Всегда возвращает кортеж, даже если строка содержит только один элемент. Строка должна содержать в точности то количество информации, как описано форматом.

Форматы данных, которые нам потребуются.

символ Значение C Значение Python Длина на 32битной машине
c char Строка из одного символа 1
i int int 4
l long int 4
L unsigned long int 4
d double float 8

Теперь собираем все вместе и посмотрим на внутреннее устройство некоторых типов данных.

О формате значений несложно догадаться.

Первое число (373) — количество указателей, на объект.

Как видно, число увеличилось на единицу, после того как мы создали еще одну ссылку на объект.

Второе число (136770080) — указатель (id) на тип объекта:

Третье число (1) — непосредственно содержимое объекта.

Наши догадки можно подтвердить, заглянув в исходный код CPython

Здесь PyObject_HEAD — макрос, общий для всех встроенных объектов, а ob_ival — значение типа long. Макрос PyObject_HEAD добавляет счетчик количества указателей на объект и указатель на родительский тип объекта — как раз то, что мы и видели.

Float

Число с плавающей запятой очень похоже на int, но представлено в памяти C значением типа double.

В этом легко убедиться:

Строка (Str)

Строка представлена в виде массива символов, оканчивающимся нулевым байтом. Также в структуре строки отдельного сохраняется ее длина, хэш от ее содержания и флаг, определяющий, хранится ли она во внутреннем кэше interned.

Макрос PyObject_VAR_HEAD включает в себя PyObject_HEAD и добавляет значение long ob_ival, в котором хранится длина строки.

Четвертое значение соответствует хэшу от строки, в чем нетрудно убедиться.

Как видно, значение sstate равно 0, так что строка сейчас не кэшируется. Попробуем ее добавить в кэш:

Кортеж (Tuple)

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

Структура tuple похоже на строку, только в ней отсутствуют специальные поля, кроме длины.

Как видим из примера, последние три элементы кортежа являются указателями на его содержимое.

Остальные базовые типы данных (unicode, list, dict, set, frozenset) можно исследовать аналогичным образом.

Что в итоге?
Тип Имя в CPython формат Формат, для вложенных объектов Длина на 32bit Длина на 64bit Память для GC*
Int PyIntObject LLl 12 24
float PyFloatObject LLd 16 24
str PyStringObject LLLli+c*(длина+1) 21+длина 37+длина
unicode PyUnicodeObject LLLLlL L*(длина+1) 28+4*длина 52+4*длина
tuple PyTupleObject LLL+L*длина 12+4*длина 24+8*длина Есть
list PyListObject L*5 L*длину 20+4*длина 40+8*длина Есть
Set/
frozenset
PySetObject L*7+(lL)*8+lL LL* длина (<=5 элементов) 100
(>5 элементов) 100+8*длина
(<=5 элементов) 200
(>5 элементов) 200+16*длина
Есть
dict PyDictObject L*7+(lLL)*8 lLL*длина (<=5 элементов) 124
(>5 элементов) 124+12*длина
(<=5 элементов) 248
(>5 элементов) 248+24*длина
Есть

* Добавляет 12 байт на 32 битной машине и 32 байта на 64 битной машине

Мы видим, что простые типы данных в Python в два-три раза больше своих прототипов на C. Разница обусловлена необходимостью хранить количество ссылок на объект и указатель на его тип (содержимое макроса PyObject_HEAD). Частично это компенсируется внутренним кэшированием, который позволяет повторно использовать ранее созданные объекты (это возможно только для неизменяемых типов).

Для строк и кортежей разница не такая значительная — добавляется некоторая постоянная величина.

А списки, словари и множества, как правило, занимают больше на 1/3, чем необходимо. Это обусловлено реализацией алгоритма добавления новых элементов, который приносит в жертву память ради экономии времени процессора.

Итак, отвечаем на вопрос в начале статьи: чтобы сохранить 1 миллион целых чисел нам потребуется 11.4 мегабайт (12*10^6 байт) на сами числа и дополнительно 3.8 мегабайт (12 + 4 + 4*10^6 байт) на кортеж, которых будет хранить на них ссылки.

UPD: Опечатки.
UPD: В подзаголовке «1 миллион целых чисел», вместо «1 миллион простых чисел»

How do I determine the size of an object in Python?

I want to know how to get size of objects like a string, integer, etc. in Python.

I am using an XML file which contains size fields that specify the size of value. I must parse this XML and do my coding. When I want to change the value of a particular field, I will check the size field of that value. Here I want to compare whether the new value that I’m gong to enter is of the same size as in XML. I need to check the size of new value. In case of a string I can say its the length. But in case of int, float, etc. I am confused.

15 Answers 15

Just use the sys.getsizeof function defined in the sys module.

sys.getsizeof(object[, default]) :

Return the size of an object in bytes. The object can be any type of object. All built-in objects will return correct results, but this does not have to hold true for third-party extensions as it is implementation specific.

Only the memory consumption directly attributed to the object is accounted for, not the memory consumption of objects it refers to.

The default argument allows to define a value which will be returned if the object type does not provide means to retrieve the size and would cause a TypeError .

getsizeof calls the object’s __sizeof__ method and adds an additional garbage collector overhead if the object is managed by the garbage collector.

See recursive sizeof recipe for an example of using getsizeof() recursively to find the size of containers and all their contents.

Usage example, in python 3.0:

If you are in python < 2.6 and don’t have sys.getsizeof you can use this extensive module instead. Never used it though.

Neuron's user avatar

How do I determine the size of an object in Python?

The answer, "Just use sys.getsizeof ", is not a complete answer.

That answer does work for builtin objects directly, but it does not account for what those objects may contain, specifically, what types, such as custom objects, tuples, lists, dicts, and sets contain. They can contain instances each other, as well as numbers, strings and other objects.

A More Complete Answer

Using 64-bit Python 3.6 from the Anaconda distribution, with sys.getsizeof , I have determined the minimum size of the following objects, and note that sets and dicts preallocate space so empty ones don’t grow again until after a set amount (which may vary by implementation of the language):

How do you interpret this? Well say you have a set with 10 items in it. If each item is 100 bytes each, how big is the whole data structure? The set is 736 itself because it has sized up one time to 736 bytes. Then you add the size of the items, so that’s 1736 bytes in total

Some caveats for function and class definitions:

Note each class definition has a proxy __dict__ (48 bytes) structure for class attrs. Each slot has a descriptor (like a property ) in the class definition.

Slotted instances start out with 48 bytes on their first element, and increase by 8 each additional. Only empty slotted objects have 16 bytes, and an instance with no data makes very little sense.

Also, each function definition has code objects, maybe docstrings, and other possible attributes, even a __dict__ .

Also note that we use sys.getsizeof() because we care about the marginal space usage, which includes the garbage collection overhead for the object, from the docs:

getsizeof() calls the object’s __sizeof__ method and adds an additional garbage collector overhead if the object is managed by the garbage collector.

Also note that resizing lists (e.g. repetitively appending to them) causes them to preallocate space, similarly to sets and dicts. From the listobj.c source code:

Historical data

Python 2.7 analysis, confirmed with guppy.hpy and sys.getsizeof :

Note that dictionaries (but not sets) got a more compact representation in Python 3.6

I think 8 bytes per additional item to reference makes a lot of sense on a 64 bit machine. Those 8 bytes point to the place in memory the contained item is at. The 4 bytes are fixed width for unicode in Python 2, if I recall correctly, but in Python 3, str becomes a unicode of width equal to the max width of the characters.

And for more on slots, see this answer.

A More Complete Function

We want a function that searches the elements in lists, tuples, sets, dicts, obj.__dict__ ‘s, and obj.__slots__ , as well as other things we may not have yet thought of.

We want to rely on gc.get_referents to do this search because it works at the C level (making it very fast). The downside is that get_referents can return redundant members, so we need to ensure we don’t double count.

Classes, modules, and functions are singletons — they exist one time in memory. We’re not so interested in their size, as there’s not much we can do about them — they’re a part of the program. So we’ll avoid counting them if they happen to be referenced.

We’re going to use a blacklist of types so we don’t include the entire program in our size count.

To contrast this with the following whitelisted function, most objects know how to traverse themselves for the purposes of garbage collection (which is approximately what we’re looking for when we want to know how expensive in memory certain objects are. This functionality is used by gc.get_referents .) However, this measure is going to be much more expansive in scope than we intended if we are not careful.

For example, functions know quite a lot about the modules they are created in.

Another point of contrast is that strings that are keys in dictionaries are usually interned so they are not duplicated. Checking for id(key) will also allow us to avoid counting duplicates, which we do in the next section. The blacklist solution skips counting keys that are strings altogether.

Whitelisted Types, Recursive visitor

To cover most of these types myself, instead of relying on the gc module, I wrote this recursive function to try to estimate the size of most Python objects, including most builtins, types in the collections module, and custom types (slotted and otherwise).

This sort of function gives much more fine-grained control over the types we’re going to count for memory usage, but has the danger of leaving important types out:

And I tested it rather casually (I should unittest it):

This implementation breaks down on class definitions and function definitions because we don’t go after all of their attributes, but since they should only exist once in memory for the process, their size really doesn’t matter too much.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *