getsizeof bytes python object memory memory-management sizeof

bytes - size of an object python



¿Cómo puedo determinar el tamaño de un objeto en Python? (8)

En C, podemos encontrar el tamaño de un int , char , etc. Quiero saber cómo obtener el tamaño de objetos como una cadena, un entero, etc. en Python.

Pregunta relacionada: ¿Cuántos bytes por elemento hay en una lista de Python (tupla)?

Estoy usando un archivo XML que contiene campos de tamaño que especifican el tamaño del valor. Debo analizar este XML y hacer mi codificación. Cuando quiero cambiar el valor de un campo en particular, verificaré el campo de tamaño de ese valor. Aquí quiero comparar si el nuevo valor que debo ingresar es del mismo tamaño que en XML. Necesito comprobar el tamaño del nuevo valor. En caso de una cadena puedo decir que es la longitud. Pero en caso de int, flotar, etc. estoy confundido.


¿Cómo puedo determinar el tamaño de un objeto en Python?

La respuesta, "Sólo use sys.getsizeof" no es una respuesta completa.

Esa respuesta funciona para los objetos incorporados directamente, pero no tiene en cuenta lo que esos objetos pueden contener, específicamente, qué tipos, como tuplas, listas, dados y conjuntos contienen. Pueden contener instancias entre sí, así como números, cadenas y otros objetos.

Una respuesta más completa

Al usar Python 3.6 de 64 bits de la distribución de Anaconda, con sys.getsizeof, he determinado el tamaño mínimo de los siguientes objetos y he notado que los conjuntos y los dicts asignan un espacio preasignado para que los vacíos no vuelvan a crecer hasta después de una cantidad establecida (que puede variar según la implementación del lenguaje):

Python 3:

Empty Bytes type scaling notes 28 int +4 bytes about every 30 powers of 2 37 bytes +1 byte per additional byte 49 str +1-4 per additional character (depending on max width) 48 tuple +8 per additional item 64 list +8 for each additional 224 set 5th increases to 736; 21nd, 2272; 85th, 8416; 341, 32992 240 dict 6th increases to 368; 22nd, 1184; 43rd, 2280; 86th, 4704; 171st, 9320 136 func def doesn''t include default args and other attrs 1056 class def no slots 56 class inst has a __dict__ attr, same scaling as dict above 888 class def with slots 16 __slots__ seems to store in mutable tuple-like structure first slot grows to 48, and so on.

como interpretas esto? Bueno, digamos que tienes un set con 10 elementos. Si cada elemento tiene 100 bytes cada uno, ¿cuál es el tamaño de toda la estructura de datos? El conjunto es el mismo 736 porque se ha dimensionado una vez hasta 736 bytes. Luego agrega el tamaño de los elementos, lo que equivale a un total de 1736 bytes.

Algunas advertencias para la función y definiciones de clase:

Tenga en cuenta que cada definición de clase tiene una __dict__ proxy __dict__ (48 bytes) para los atributos de clase. Cada ranura tiene un descriptor (como una property ) en la definición de clase.

Las instancias ranuradas comienzan con 48 bytes en su primer elemento, y aumentan en 8 cada uno adicional. Sólo los objetos con espacios vacíos tienen 16 bytes, y una instancia sin datos tiene muy poco sentido.

Además, cada definición de función tiene objetos de código, tal vez cadenas de documentación y otros atributos posibles, incluso un __dict__ .

Análisis de Python 2.7, confirmado con guppy.hpy y sys.getsizeof :

Bytes type empty + scaling notes 24 int NA 28 long NA 37 str + 1 byte per additional character 52 unicode + 4 bytes per additional character 56 tuple + 8 bytes per additional item 72 list + 32 for first, 8 for each additional 232 set sixth item increases to 744; 22nd, 2280; 86th, 8424 280 dict sixth item increases to 1048; 22nd, 3352; 86th, 12568 * 120 func def doesn''t include default args and other attrs 64 class inst has a __dict__ attr, same scaling as dict above 16 __slots__ class with slots has no dict, seems to store in mutable tuple-like structure. 904 class def has a proxy __dict__ structure for class attrs 104 old class makes sense, less stuff, has real dict though.

Tenga en cuenta que los diccionarios ( pero no los conjuntos ) obtuvieron una representación más compacta en Python 3.6

Creo que 8 bytes por elemento adicional a referencia tienen mucho sentido en una máquina de 64 bits. Esos 8 bytes apuntan al lugar en la memoria donde se encuentra el elemento. Los 4 bytes tienen un ancho fijo para Unicode en Python 2, si recuerdo bien, pero en Python 3, str se convierte en un Unicode de ancho igual al ancho máximo de los caracteres.

(Y para más información sobre las tragamonedas, vea esta respuesta )

Visitante recursivo para una función más completa

Para cubrir la mayoría de estos tipos, escribí esta función recursiva para tratar de estimar el tamaño de la mayoría de los objetos de Python, incluidos la mayoría de los incorporados, los tipos en el módulo de colecciones y los tipos personalizados (ranurados y de otro tipo):

import sys from numbers import Number from collections import Set, Mapping, deque try: # Python 2 zero_depth_bases = (basestring, Number, xrange, bytearray) iteritems = ''iteritems'' except NameError: # Python 3 zero_depth_bases = (str, bytes, Number, range, bytearray) iteritems = ''items'' def getsize(obj_0): """Recursively iterate to sum size of object & members.""" _seen_ids = set() def inner(obj): obj_id = id(obj) if obj_id in _seen_ids: return 0 _seen_ids.add(obj_id) size = sys.getsizeof(obj) if isinstance(obj, zero_depth_bases): pass # bypass remaining control flow and return elif isinstance(obj, (tuple, list, Set, deque)): size += sum(inner(i) for i in obj) elif isinstance(obj, Mapping) or hasattr(obj, iteritems): size += sum(inner(k) + inner(v) for k, v in getattr(obj, iteritems)()) # Check for custom object instances - may subclass above too if hasattr(obj, ''__dict__''): size += inner(vars(obj)) if hasattr(obj, ''__slots__''): # can have __slots__ with __dict__ size += sum(inner(getattr(obj, s)) for s in obj.__slots__ if hasattr(obj, s)) return size return inner(obj_0)

Y lo probé de forma casual (debería probarlo):

>>> getsize([''a'', tuple(''bcd''), Foo()]) 344 >>> getsize(Foo()) 16 >>> getsize(tuple(''bcd'')) 194 >>> getsize([''a'', tuple(''bcd''), Foo(), {''foo'': ''bar'', ''baz'': ''bar''}]) 752 >>> getsize({''foo'': ''bar'', ''baz'': ''bar''}) 400 >>> getsize({}) 280 >>> getsize({''foo'':''bar''}) 360 >>> getsize(''foo'') 40 >>> class Bar(): ... def baz(): ... pass >>> getsize(Bar()) 352 >>> getsize(Bar().__dict__) 280 >>> sys.getsizeof(Bar()) 72 >>> getsize(Bar.__dict__) 872 >>> sys.getsizeof(Bar.__dict__) 280

Se descompone en las definiciones de clase y en la función porque no busco todos sus atributos, pero como solo deben existir una vez en la memoria para el proceso, su tamaño realmente no importa demasiado.


Aquí hay un guión rápido que escribí basado en las respuestas anteriores a los tamaños de lista de todas las variables

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


Después de haber encontrado este problema muchas veces, escribí una pequeña función (inspirada en la respuesta de @ aaron-hall) y pruebas que hacen lo que habría esperado que hiciera sys.getsizeof:

https://github.com/bosswissam/pysize

Si estás interesado en la historia de fondo, aquí está

EDITAR: Adjuntar el código de abajo para una fácil referencia. Para ver el código más actualizado, verifique el enlace de 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


El módulo asizeof del paquete asizeof puede hacer esto.

Use de la siguiente manera:

from pympler import asizeof asizeof.asizeof(my_object)

A diferencia de sys.getsizeof , funciona para tus objetos de creación propia . Incluso funciona con 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

Como se mentioned ,

El tamaño del código (byte) de objetos como clases, funciones, métodos, módulos, etc. se puede incluir configurando el code=True opción code=True .

Y si necesita otra vista sobre datos en vivo, Pympler es

el módulo muppy se utiliza para la supervisión en línea de una aplicación Python y el módulo Class Tracker proporciona un análisis fuera de línea de la vida útil de los objetos Python seleccionados.


Esto puede ser más complicado de lo que parece, dependiendo de cómo quiera contar las cosas. Por ejemplo, si tiene una lista de entradas, ¿desea el tamaño de la lista que contiene las referencias a las entradas? (es decir, solo la lista, no lo que contiene), o si desea incluir los datos reales señalados, en cuyo caso debe tratar con referencias duplicadas, y cómo evitar el recuento doble cuando dos objetos contienen referencias a el mismo objeto

Es posible que desee echar un vistazo a uno de los perfiladores de memoria de Python, como pysizer para ver si satisfacen sus necesidades.


Para matrices numpy, getsizeof no funciona, para mí siempre devuelve 40 por alguna razón:

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

Entonces (en ipython):

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

Afortunadamente, sin embargo:

In [66]: A.nbytes Out[66]: 80 In [67]: B.nbytes Out[67]: 80000


Primero: una respuesta.

import sys try: print sys.getsizeof(object) except AttributeError: print "sys.getsizeof exists in Python ≥2.6"

Discusión:
En Python, nunca se puede acceder a direcciones de memoria "directas". ¿Por qué, entonces, necesitaría o querría saber cuántas direcciones están ocupadas por un objeto determinado? Es una pregunta que es completamente inapropiada en ese nivel de abstracción. Cuando estás pintando tu casa, no preguntas qué frecuencias de luz son absorbidas o reflejadas por cada uno de los átomos que forman parte de la pintura, solo preguntas qué color es: los detalles de las características físicas que crean ese color. están al lado del punto. De manera similar, el número de bytes de memoria que ocupa un objeto de Python dado está al lado del punto.

Entonces, ¿por qué estás tratando de usar Python para escribir código C? :)


Simplemente use la función sys.getsizeof definida en el módulo sys .

sys.getsizeof(object[, default]) :

Devuelve el tamaño de un objeto en bytes. El objeto puede ser cualquier tipo de objeto. Todos los objetos incorporados devolverán los resultados correctos, pero esto no tiene por qué ser cierto para las extensiones de terceros, ya que es específico de la implementación.

El argumento default permite definir un valor que se devolverá si el tipo de objeto no proporciona los medios para recuperar el tamaño y causaría un TypeError .

getsizeof llama al método __sizeof__ del objeto y agrega una sobrecarga adicional al recolector de basura si el objeto es administrado por el recolector de basura.

Ejemplo de uso, en 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

Si está en Python <2.6 y no tiene sys.getsizeof , puede usar este módulo extenso en su lugar. Aunque nunca lo usé.