Как определить размер объекта в Python?

Я хочу знать, как получить размер таких объектов, как строка, целое число и т. д. В Python.

Связанный вопрос: Сколько байтов на элемент в списке (кортеже) Python?

Я использую XML-файл, который содержит поля размера, в которых указывается размер значения. Я должен проанализировать этот XML и написать код. Когда я хочу изменить значение определенного поля, я проверю поле размера этого значения. Здесь я хочу сравнить, имеет ли новое значение, которое я собираюсь ввести, тот же размер, что и в XML. Мне нужно проверить размер нового значения. В случае строки я могу сказать ее длину. Но в случае int, float и т. д. Я запутался.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
788
0
736 214
12

Ответы 12

Просто используйте функцию sys.getsizeof, определенную в модуле sys.

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.

Пример использования в Python 3.0:

>>> import sys
>>> x = 2
>>> sys.getsizeof(x)
24
>>> sys.getsizeof(sys.getsizeof)
32
>>> sys.getsizeof('this')
38
>>> sys.getsizeof('this also')
48

Если вы используете python <2.6 и у вас нет sys.getsizeof, вы можете вместо этого использовать этот обширный модуль. Но никогда не использовал.

Добавьте к заявлению об отказе от ответственности, что это не относится к вложенным объектам, вложенным диктовкам или диктовкам в списках и т. д.

JohnnyM 16.08.2015 12:22

Умм ... sys.sizeof (c) равно 32, даже если у экземпляра класса 50 атрибутов! Кажется, что-то не так! Попробуйте это: d = {k: v for k, v in zip('ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy', range(50))}class C(object): def __init__(self, **kwargs): _ = {setattr(self, k, v) for k, v in kwargs.items()}c = C(**d)sys.getsizeof(d) 1676 sys.getsizeof(c) 32

ChaimG 21.02.2017 20:26

@ChaimG, потому что каждый объект использует только 32 байта !! Остальное - это ссылки на другие объекты. Если вы хотите учитывать объекты, на которые имеются ссылки, вам необходимо определить метод __sizeof__ для своего класса. Встроенный класс python dict определяет его, поэтому вы получаете правильный результат при использовании объекта типа dict.

nosklo 11.04.2017 20:23

Заявление об отказе от ответственности и исключения из этого рабочего документа охватывают почти все варианты использования, делающие функцию getsizeof малоценной из коробки.

Robino 28.06.2017 19:57

Очевидно, sys.getsizeof недоступен в PyPy. Есть ли общий обходной путь для этого?

conorliv 29.01.2018 22:03

почему целое число 2 хранится в 24 байтах?

Saher Ahwal 20.03.2018 02:59

@SaherAhwal это не просто целое число, а полноценный объект с методами, атрибутами, адресами ...

nosklo 20.03.2018 20:29

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

Вы можете взглянуть на один из профилировщиков памяти Python, например писатель, чтобы узнать, соответствуют ли они вашим потребностям.

Для массивов numpy getsizeof не работает - для меня он по какой-то причине всегда возвращает 40:

from pylab import *
from sys import getsizeof
A = rand(10)
B = rand(10000)

Затем (в ipython):

In [64]: getsizeof(A)
Out[64]: 40

In [65]: getsizeof(B)
Out[65]: 40

К счастью:

In [66]: A.nbytes
Out[66]: 80

In [67]: B.nbytes
Out[67]: 80000

> Все встроенные объекты будут возвращать правильные результаты, но это не обязательно должно выполняться для сторонних расширений, поскольку это зависит от реализации. docs.python.org/library/sys.html#sys.getsizeof

warvariuc 30.06.2011 15:59

«Если вы используете массив numpy (docs.scipy.org/doc/numpy/reference/arrays.ndarray.html), вы можете использовать атрибут 'ndarray.nbytes', чтобы оценить его размер в памяти». stackoverflow.com/a/15591157/556413

glarrain 23.04.2013 02:24

Я бы предположил, что 40 байт - это правильно, однако getsizeof() дает вам только размер объекта (заголовок массива), а не данных внутри. То же самое для контейнеров python, где sys.getsizeof([1,2,4]) == sys.getsizeof([1,123**456,4]) == 48, а sys.getsizeof(123**456) = 436

yota 15.05.2014 17:57

Похоже, что функция getsizeof() была изменена в какой-то момент, чтобы вернуть ожидаемое значение.

dshin 22.08.2017 19:54

Вот быстрый сценарий, который я написал на основе предыдущих ответов о размерах списка всех переменных.

for i in dir():
    print (i, sys.getsizeof(eval(i)) )

Это не неправильно, это неоднозначно. sys.getsizeof всегда будет возвращать значение, поэтому нет необходимости терять производительность с помощью try..except.

der_fenix 14.07.2014 12:14

о, это хороший момент, и я не думал об этом - код в той форме, в которой он сейчас, просто показывает, как он был написан в хронологическом порядке - сначала я знал о numpy (следовательно, nbytes), затем я нашел более общее решение . Спасибо вам за разъяснение _/\_

alexey 15.07.2014 02:32

Модуль asizeof пакета Пимплер может это сделать.

Используйте следующим образом:

from pympler import asizeof
asizeof.asizeof(my_object)

В отличие от sys.getsizeof, это работает для ваших созданных вами объектов. Он даже работает с numpy.

>>> asizeof.asizeof(tuple('bcd'))
200
>>> asizeof.asizeof({'foo': 'bar', 'baz': 'bar'})
400
>>> asizeof.asizeof({})
280
>>> asizeof.asizeof({'foo':'bar'})
360
>>> asizeof.asizeof('foo')
40
>>> asizeof.asizeof(Bar())
352
>>> asizeof.asizeof(Bar().__dict__)
280
>>> A = rand(10)
>>> B = rand(10000)
>>> asizeof.asizeof(A)
176
>>> asizeof.asizeof(B)
80096

Как упомянул,

The (byte)code size of objects like classes, functions, methods, modules, etc. can be included by setting option code=True.

А если вам нужен другой взгляд на живые данные, Pympler's

module muppy is used for on-line monitoring of a Python application and module Class Tracker provides off-line analysis of the lifetime of selected Python objects.

эта функция довольно медленная для больших объектов. Существует ли «быстрый» эквивалент, который работает для самосозданных объектов?

Shuklaswag 07.06.2017 21:42

Я еще не тестировал, но org.apache.spark.util.SizeEstimator может быть актуален

Shuklaswag 08.06.2017 17:28

@Shuklaswag: если вы используете искру, вполне может быть. Как вы думаете, конверсия + оценка Java быстрее, чем встроенные методы Python? Или я неправильно понял?

serv-inc 08.06.2017 19:28

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

mtraceur 15.03.2018 11:22

Я получаю исключение TypeError: «Объект« NoneType »не вызывается» всякий раз, когда мой настраиваемый объект имеет в своем «дереве» подобъект со значением None. Есть ли какое-нибудь быстрое решение?

James Hirschorn 08.09.2018 22:19

@JamesHirschorn: Ты мог бы опубликовать отчет об ошибке. Не могли бы вы дать MCVE? Использование asizeof.asizeof({"hello": None}) и asizeof.asizeof({"hello": {"world": None}}) оба работали с Pympler 0.6.

serv-inc 08.09.2018 23:24

Да, оба ваших примера у меня тоже сработали. Сложность с MCVE заключается в том, что мой код основан на клоне github другого автора. Будет ли достаточно не минимального CVE от github?

James Hirschorn 09.09.2018 04:37

@JamesHirschorn: все, что нужно отлаживать, желательно с трассировкой стека, или попробовать json.dump рассматриваемого объекта.

serv-inc 09.09.2018 07:23

@ serv-inc: Хорошо, я добавлю трассировку и json.dump в отчет об ошибке.

James Hirschorn 12.09.2018 09:37

@JamesHirschorn: неплохо выглядит. Если json.dump не работает, возможно, pickle.dumps работает.

serv-inc 12.09.2018 11:02

@ serv-inc: Сообщите мне, если я вам понадоблюсь, чтобы протестировать его, потому что в противном случае в моей программе не будет утечки памяти, поэтому во мне нет срочной необходимости.

James Hirschorn 18.09.2018 18:11

Результаты в байтах, килобайтах, мегабайтах ...?

ihavenoidea 26.03.2020 04:51

@ihavenoidea: bytes (просто представьте, что каждый объект python занимает 280 кбайт)

serv-inc 27.03.2020 13:03

Столкнувшись с этой проблемой много раз, я написал небольшую функцию (вдохновленную ответом @aaron-hall) и тесты, которые делают то, что я ожидал от sys.getsizeof:

https://github.com/bosswissam/pysize

Если вас интересует предыстория, вот

Обновлено: прикрепите приведенный ниже код для удобства. Чтобы увидеть самый последний код, проверьте ссылку на github.

    import sys

    def get_size(obj, seen=None):
        """Recursively finds size of objects"""
        size = sys.getsizeof(obj)
        if seen is None:
            seen = set()
        obj_id = id(obj)
        if obj_id in seen:
            return 0
        # Important mark as seen *before* entering recursion to gracefully handle
        # self-referential objects
        seen.add(obj_id)
        if isinstance(obj, dict):
            size += sum([get_size(v, seen) for v in obj.values()])
            size += sum([get_size(k, seen) for k in obj.keys()])
        elif hasattr(obj, '__dict__'):
            size += get_size(obj.__dict__, seen)
        elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):
            size += sum([get_size(i, seen) for i in obj])
        return size

Python 3.8 (первый квартал 2019 г.) изменит некоторые результаты sys.getsizeof, как объявлено здесь Раймонда Хеттингера:

Python containers are 8 bytes smaller on 64-bit builds.

tuple ()  48 -> 40       
list  []  64 ->56
set()    224 -> 216
dict  {} 240 -> 232

Это происходит после того, как Выпуск 33597 и Инада Наоки (methane) поработали над Compact PyGC_Head и PR 7043

This idea reduces PyGC_Head size to two words.

Currently, PyGC_Head takes three words; gc_prev, gc_next, and gc_refcnt.

  • gc_refcnt is used when collecting, for trial deletion.
  • gc_prev is used for tracking and untracking.

So if we can avoid tracking/untracking while trial deletion, gc_prev and gc_refcnt can share same memory space.

См. совершить d5c875b:

Removed one Py_ssize_t member from PyGC_Head.
All GC tracked objects (e.g. tuple, list, dict) size is reduced 4 or 8 bytes.

Если вам не нужен точный размер объекта, но нужно примерно знать, насколько он велик, один быстрый (и грязный) способ - позволить программе работать, спать в течение длительного периода времени и проверить использование памяти (например, : Монитор активности Mac) этим конкретным процессом Python. Это было бы эффективно, когда вы пытаетесь найти размер одного большого объекта в процессе Python. Например, недавно я хотел проверить использование памяти новой структурой данных и сравнить ее со структурой данных набора Python. Сначала я записал элементы (слова из большой общедоступной книги) в набор, затем проверил размер процесса, а затем проделал то же самое с другой структурой данных. Я обнаружил, что процесс Python с набором занимает в два раза больше памяти, чем новая структура данных. Опять же, вы не сможете точно сказать, что память, используемая процессом, равна размеру объекта. По мере увеличения размера объекта он становится близким, поскольку память, потребляемая остальной частью процесса, становится незначительной по сравнению с размером объекта, который вы пытаетесь отслеживать.

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

Tom Wyllie 11.08.2019 22:12

@TomWyllie, Спасибо, но голосование против этого ответа имеет негативный оттенок, что сам ответ неверен и ничего не дает. Упомянутый мной метод может не быть реализован в Python, но это удобный способ получить приблизительную оценку размера объекта Python. Я знал, что не отвечаю на точный вопрос, однако этот метод может быть полезен для кого-то другого, чтобы получить аналогичный результат.

picmate 涅 03.09.2019 21:31

Вы можете использовать getSizeof (), как указано ниже, для определения размера объекта.

import sys
str1 = "one"
int_element=5
print("Memory size of '"+str1+"' = "+str(sys.getsizeof(str1))+ " bytes")
print("Memory size of '"+ str(int_element)+"' = "+str(sys.getsizeof(int_element))+ " bytes")

Используйте sys.getsizeof (), если вы НЕ хотите включать размеры связанных (вложенных) объектов.

Однако, если вы хотите подсчитать подобъекты, вложенные в списки, словари, наборы, кортежи - а обычно это именно то, что вы ищете - используйте рекурсивную функцию глубокий sizeof (), как показано ниже:

import sys
def sizeof(obj):
    size = sys.getsizeof(obj)
    if isinstance(obj, dict): return size + sum(map(sizeof, obj.keys())) + sum(map(sizeof, obj.values()))
    if isinstance(obj, (list, tuple, set, frozenset)): return size + sum(map(sizeof, obj))
    return size

Вы также можете найти эту функцию в наборе инструментов изящный вместе со многими другими полезными однострочниками:

https://github.com/mwojnars/nifty/blob/master/util.py

Этот - правильный ответ. Это заслуживает вашего одобрения.
ChaimG 12.02.2021 08:24

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

import pickle

## let o be the object whose size you want to measure
size_estimate = len(pickle.dumps(o))

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

Я использую этот трюк ... Может быть, не будет точным для небольших объектов, но я думаю, что он намного точнее для сложного объекта (например, поверхности pygame), чем sys.getsizeof ()

import pygame as pg
import os
import psutil
import time


process = psutil.Process(os.getpid())
pg.init()    
vocab = ['hello', 'me', 'you', 'she', 'he', 'they', 'we',
         'should', 'why?', 'necessarily', 'do', 'that']

font = pg.font.SysFont("monospace", 100, True)

dct = {}

newMem = process.memory_info().rss  # don't mind this line
Str = f'store ' + f'Nothing \tsurface use about '.expandtabs(15) + \
      f'0\t bytes'.expandtabs(9)  # don't mind this assignment too

usedMem = process.memory_info().rss

for word in vocab:
    dct[word] = font.render(word, True, pg.Color("#000000"))

    time.sleep(0.1)  # wait a moment

    # get total used memory of this script:
    newMem = process.memory_info().rss
    Str = f'store ' + f'{word}\tsurface use about '.expandtabs(15) + \
          f'{newMem - usedMem}\t bytes'.expandtabs(9)

    print(Str)
    usedMem = newMem

В моих окнах 10, python 3.7.3 вывод:

store hello          surface use about 225280    bytes
store me             surface use about 61440     bytes
store you            surface use about 94208     bytes
store she            surface use about 81920     bytes
store he             surface use about 53248     bytes
store they           surface use about 114688    bytes
store we             surface use about 57344     bytes
store should         surface use about 172032    bytes
store why?           surface use about 110592    bytes
store necessarily    surface use about 311296    bytes
store do             surface use about 57344     bytes
store that           surface use about 110592    bytes

Другие вопросы по теме