Question Comment puis-je déterminer la taille d'un objet en Python?


En C, on peut trouver la taille d'un int, char, etc. Je veux savoir comment obtenir la taille des objets comme une chaîne, un entier, etc. en Python.

Question connexe: Combien y a-t-il d'octets 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 changer la valeur d'un champ particulier, je vais vérifier le champ de taille de cette valeur. Ici, je veux comparer si la nouvelle valeur que je vais entrer est de la même taille qu'en XML. Je dois vérifier la taille de la nouvelle valeur. Dans le cas d'une chaîne je peux dire sa longueur. Mais en cas de int, float, etc. Je suis confus.


428
2018-01-16 05:07


origine


Réponses:


Utilisez simplement le sys.getsizeof fonction définie dans le sys module.

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 reviendront   des résultats corrects, mais cela ne   doit être vrai pour les tiers   extensions comme il est implémentation   spécifique.

le default l'argument permet de définir   une valeur qui sera retournée si le   type d'objet ne fournit pas de moyens pour   récupérer la taille et provoquerait un    TypeError.

getsizeof appelle l'objet    __sizeof__ méthode et ajoute un supplément de garbage collector   si l'objet est géré par le   Éboueur.

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 n'avez pas sys.getsizeof vous pouvez utiliser ce module complet au lieu. Je ne l'ai jamais utilisé cependant.


464
2018-01-16 10:42



Comment puis-je déterminer la taille d'un objet en Python?

La réponse "utilisez simplement sys.getsizeof" n'est pas une réponse complète.

Cette réponse Est-ce que travailler directement pour les objets intégrés, mais ne tient pas compte de ce que ces objets peuvent contenir, en particulier des types, tels que des tuples, des listes, des dicts et des ensembles. Ils peuvent contenir des instances les uns des autres, ainsi que des nombres, des chaînes et d'autres objets.

Une réponse plus complète

En utilisant Python 3.6 64 bits de la distribution Anaconda, avec sys.getsizeof, j'ai déterminé la taille minimale des objets suivants, et notez que définit et affiche l'espace préalloué afin que les espaces vides ne grandissent plus avant une quantité définie (ce qui peut varient selon l'implémentation de la langue):

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 interprétez-vous cela? Eh bien, disons que vous avez un ensemble de 10 objets. Si chaque élément a 100 octets chacun, quelle est la taille de la structure de données? L'ensemble est 736 lui-même, car il a été dimensionné une fois à 736 octets. Ensuite, vous ajoutez la taille des éléments, de sorte que 1736 octets au total

Quelques mises en garde concernant les définitions de fonctions et de classes:

Notez que chaque définition de classe a un proxy __dict__ (48 bytes) structure pour la classe attrs. Chaque slot a un descripteur (comme un property) dans la définition de classe.

Les instances à créneaux commencent avec 48 octets sur leur premier élément et augmentent de 8 chaque fois. Seuls les objets à fente vides ont 16 octets, et une instance sans données a très peu de sens.

En outre, chaque définition de fonction a des objets de code, peut-être docstrings, et d'autres attributs possibles, même un __dict__.

Analyse Python 2.7, confirmée avec 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 des ensembles) Avoir un plus représentation compacte en Python 3.6

Je pense que 8 octets par élément supplémentaire à référencer ont beaucoup de sens sur une machine 64 bits. Ces 8 octets indiquent l'endroit dans la 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 unicode de largeur égale à la largeur maximale des caractères.

(Et pour en savoir plus sur les machines à sous, 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, des types dans le module des collections, et des types personnalisés (fendus 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é plutôt de manière décontractée (je devrais le remettre à plus tard):

>>> 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 en quelque sorte sur les définitions de classe et les définitions de fonctions parce que je ne vais pas après tous leurs attributs, mais comme ils ne devraient exister qu'une seule fois en mémoire pour le processus, leur taille importe peu.


185
2018-05-19 04:26



Pour les tableaux numpy, 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)

Ensuite (en 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

71
2017-07-30 16:33



le Pympler paquets asizeof le module peut le faire.

Utilisez comme suit:

from pympler import asizeof
asizeof.asizeof(my_object)

contrairement à sys.getsizeof, il travaille 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é,

La taille du code (octet) des objets tels que les classes, fonctions, méthodes, modules, etc. peut être incluse en définissant l'option code=True.

Et si vous avez besoin d'autre vue sur les données en direct, Pympler

module muppy est utilisé pour la surveillance en ligne d'une application Python   et module Class Tracker fournit une analyse hors ligne de la durée de vie de   objets Python sélectionnés.


43
2017-11-10 14:01



Cela peut être plus compliqué qu'il n'y paraît en fonction de la façon dont vous voulez compter les choses. Par exemple, si vous avez une liste d'ints, voulez-vous la taille de la liste contenant le les références aux ints? (c'est-à-dire liste seulement, pas ce qui est contenu dedans), ou voulez-vous inclure les données réelles pointées, auquel cas vous devez traiter des références en double, et comment empêcher le double comptage quand deux objets contiennent des références à le même objet

Vous pouvez jeter un oeil à l'un des profileurs de mémoire python, tels que pysizer pour voir s'ils répondent à vos besoins.


11
2018-01-16 13:00



Voici un script rapide que j'ai écrit basé sur les réponses précédentes à la liste des tailles de toutes les variables

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

7
2018-03-04 17:34



Ayant souvent rencontré ce problème moi-même, j'ai écrit une petite fonction (inspirée de la réponse de @ aaron-hall) et des tests qui font ce que je m'attendais à ce que sys.getsizeof fasse:

https://github.com/bosswissam/pysize

Si vous êtes intéressé par l'histoire, C'est ici

EDIT: Joindre le code ci-dessous pour une référence facile. Pour voir le code le plus récent, 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
2017-07-21 22:21



Premier: 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 jamais accéder aux adresses mémoire "directes". Pourquoi, alors, auriez-vous besoin ou voulez-vous savoir combien de telles adresses sont occupées par un objet donné? C'est une question totalement inappropriée à ce niveau d'abstraction. Lorsque vous peignez votre maison, vous ne demandez pas quelles sont les fréquences de la lumière qui sont absorbées ou réfléchies par chacun des atomes constituant la peinture, vous demandez simplement de quelle couleur il s'agit - 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
2018-01-16 06:58