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 ,
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óduloClass 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 unTypeError
.
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é.