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.

454
demandé sur Community 2009-01-16 08:07:12

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 un TypeError .

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é.

491
répondu nosklo 2018-01-31 16:08:22

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.

203
répondu Aaron Hall 2018-07-04 18:27:22

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
74
répondu Mike Dewar 2010-07-30 16:33:00

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é ,

(octet)de la taille du code d'objets, tels que les classes, les fonctions, méthodes, modules,etc. peut être inclus en paramétrant l'option code=True .

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 module Class Tracker fournit une analyse hors ligne de la durée de vie de objets Python sélectionnés.

51
répondu serv-inc 2018-03-15 10:06:49

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.

11
répondu Brian 2009-01-16 13:00:14

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)) )
8
répondu alexey 2018-02-02 21:14:32

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
5
répondu wissam 2016-07-21 22:21:07

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? :)

-4
répondu Jeff Shannon 2009-01-16 13:06:49