Comment déterminer la taille d'un objet en Python?
en C, nous pouvons trouver la taille d'un int
, char
, etc. Je veux savoir comment obtenir la taille des objets comme une chaîne de caractères, entier, etc. en Python.
question connexe: combien d'octets y a-t-il par élément dans une liste Python (tuple)?
j'utilise un fichier XML qui contient des champs de taille qui spécifient la taille de la valeur. Je dois analyser ce XML et faire mon codage. Quand je veux modifier la valeur d'un particulier champ, je vais vérifier le champ de taille de cette valeur. Ici je veux comparer si la nouvelle valeur que je suis gong pour entrer est de la même taille que dans XML. Je dois vérifier la taille de la nouvelle valeur. Dans le cas d'une corde je peux dire sa la longueur. Mais en cas d'int, float, etc. Je suis confus.
8 réponses
il suffit d'utiliser le système .getsizeof fonction définie dans le module sys
.
sys.getsizeof(object[, default])
:renvoie la taille d'un objet en octets. L'objet peut être n'importe quel type d'objet. Tous les objets intégrés retourneront des résultats corrects, mais ce n'est pas ont à vrai pour les tiers extensions en cours de mise en œuvre spécifique.
le
default
argument permet de définir une valeur qui sera retournée si le le type d'objet ne fournit pas les moyens récupérer la taille et causerait unTypeError
.
getsizeof
appelle l'objet La méthode__sizeof__
et ajoute un collecteur d'ordures supplémentaire au-dessus si l'objet est géré par la garbage collector.
exemple d'utilisation, 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 vous êtes en python < 2.6 et ne pas avoir sys.getsizeof
vous pouvez utiliser ce module étendu à la place. N'a jamais été utilisé.
Comment déterminer la taille d'un objet en Python?
La réponse, "il suffit d'utiliser sys.getsizeof" n'est pas une réponse complète.
Que répondre à ne travail intégrées directement les objets, mais il ne tient pas compte de ce que ces objets peuvent contenir, en particulier, quels sont les types, tels que les tuples, listes, dicts, et les ensembles contiennent. Ils peuvent contenir des instances les uns les autres, ainsi que des nombres, les chaînes et autres objets.
Une Réponse Plus Complète
utilisant 64 bits Python 3.6 de la distribution Anaconda, avec sys.getsizeof, j'ai déterminé la taille minimale des objets suivants, et note que les ensembles et les dicts préallocent l'espace de sorte que les vides ne croissent pas de nouveau jusqu'à ce qu'après un montant défini (qui peut varier par l'implémentation du langage):
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.
Comment allez-vous interpréter cela? Disons que vous avez un ensemble avec 10 articles. Si chaque élément est de 100 octets chacun, quelle est la taille de l'ensemble de la structure de données? Le jeu est 736 lui-même parce qu'il a dimensionné une fois à 736 octets. Puis vous ajoutez la taille des éléments, ce qui fait 1736 octets au total
Quelques mises en garde pour la fonction et les définitions de classe:
Note chaque définition de classe a une structure de remplacement __dict__
(48 octets) pour les attrs de classe. Chaque logement dispose d'un descripteur (comme un property
) dans la définition de classe.
slotted instances commencent avec 48 octets sur leur premier élément, et augmentent de 8 chaque supplémentaire. Seuls les objets vides ont 16 octets, et une instance sans données a très peu de sens.
aussi, chaque définition de fonction a des objets de code, peut-être des docstrings, et d'autres attributs possibles, même un __dict__
.
analyse Python 2.7, confirmée par guppy.hpy
et 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.
notez que les dictionnaires ( mais pas les ensembles ) ont obtenu un plus représentation compacte en Python 3.6
je pense que 8 octets par item supplémentaire de référence fait beaucoup de sens sur une machine 64 bits. Ces 8 octets pointent vers l'endroit en mémoire où se trouve l'élément contenu. Les 4 octets sont une largeur fixe pour unicode en Python 2, si je me souviens bien, mais en Python 3, str devient un unicode de largeur égale à la largeur des caractères.
(et pour plus sur les créneaux, voir cette réponse )
visiteur récursif pour une fonction plus complète
pour couvrir la plupart de ces types, j'ai écrit cette fonction récursive pour essayer d'estimer la taille de la plupart des objets Python, y compris la plupart des builtins, types dans le module collections, et types personnalisés (slotted et autres):
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)
et je l'ai testé assez désinvoltement (je devrais le tester en unité):
>>> 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
il se décompose un peu sur les définitions de classe et de fonction parce que je ne vais pas après tous leurs attributs, mais comme ils ne devraient exister qu'une fois dans la mémoire pour le processus, leur taille ne compte vraiment pas trop.
pour les tableaux vides, getsizeof
ne fonctionne pas - pour moi, il retourne toujours 40 pour une raison quelconque:
from pylab import *
from sys import getsizeof
A = rand(10)
B = rand(10000)
, Puis (dans ipython):
In [64]: getsizeof(A)
Out[64]: 40
In [65]: getsizeof(B)
Out[65]: 40
heureusement, cependant:
In [66]: A.nbytes
Out[66]: 80
In [67]: B.nbytes
Out[67]: 80000
le module Pympler packaging asizeof
peut le faire.
utiliser comme suit:
from pympler import asizeof
asizeof.asizeof(my_object)
contrairement à sys.getsizeof
, il fonctionne pour vos objets auto-créés . Il fonctionne même avec 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
Comme mentionné ,
et si vous avez besoin d'autre vue sur les données en direct, Pympler's
module
muppy
est utilisé pour la surveillance en ligne d'une application Python et le moduleClass Tracker
fournit une analyse hors ligne de la durée de vie de objets Python sélectionnés.
Cela peut être plus compliqué qu'il n'y paraît, selon la façon dont vous voulez compter les choses. Par exemple, si vous avez une liste d'entiers, voulez-vous de la taille de la liste contenant les références pour les services de renseignements? (IE. liste uniquement, et non de ce qui est contenu dans celui-ci), ou voulez-vous d'inclure les données réelles a souligné, dans ce cas, vous devez traiter avec des références en double, et comment éviter le double comptage des deux objets qui contiennent des références à l'objet même.
vous pouvez jeter un oeil à l'un des profileurs de mémoire de python, tels que pysizer pour voir s'ils répondent à vos besoins.
voici un script rapide que j'ai écrit basé sur les réponses précédentes aux tailles de liste de toutes les variables
for i in dir():
print (i, sys.getsizeof(eval(i)) )
ayant moi-même rencontré ce problème à plusieurs reprises, j'ai écrit une petite fonction (inspirée de la réponse de @aaron-hall) et des tests qui font ce que j'aurais attendu de sys.getsizeof à faire:
https://github.com/bosswissam/pysize
si vous êtes intéressé par l'histoire, voici
EDIT: Attacher le code ci-dessous pour référence facile. Pour voir le code le plus à jour, veuillez vérifier le lien 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
d'Abord: une réponse.
import sys
try: print sys.getsizeof(object)
except AttributeError:
print "sys.getsizeof exists in Python ≥2.6"
Discussion:
En Python, vous ne pouvez pas accéder aux adresses mémoires "directes". Pourquoi, alors, auriez-vous besoin ou veulent savoir comment beaucoup de ces logements sont occupés par un objet donné?? C'est une question totalement inappropriée à ce niveau d'abstraction. Quand vous peignez votre maison, vous ne demandez pas quelles fréquences de lumière sont absorbées ou réfléchies par chacun des atomes constitutifs dans le paint, vous demandez juste quelle couleur il est -- les détails des caractéristiques physiques qui créent cette couleur sont à côté du point. De même, le nombre d'octets de mémoire qu'un objet Python donné occupe est à côté du point.
alors, pourquoi essayez-vous D'utiliser Python pour écrire du code C? :)