Je veux savoir comment obtenir la taille d'objets comme une chaîne, un entier, etc. en Python.
Question connexe: combien d'octets par élément y a-t-il 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. Lorsque je souhaite modifier la valeur d'un champ particulier, je vérifie 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 d'int, float, etc. je suis confus.
__sizeof__
méthode pour votre classe. Ladict
classe python intégrée le définit, c'est pourquoi vous obtenez le résultat correct lorsque vous utilisez un objet de typedict
.getsizeof
fonction de peu de valeur prête à l' emploi .La réponse, "Il suffit d'utiliser sys.getsizeof" n'est pas une réponse complète.
Cette réponse fait le travail pour les objets directement builtin, mais il ne tient pas compte de ce que ces objets peuvent contenir, en particulier, quels types, tels que des objets personnalisés, tuples, listes, dicts et ensembles contiennent. Ils peuvent contenir des instances entre elles, ainsi que des nombres, des chaînes et d'autres objets.
Une réponse plus complète
À l'aide de 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 les ensembles et les images préallouent de sorte que les espaces vides ne se développent plus qu'après une quantité définie (ce qui peut varient selon la mise en œuvre de la langue):
Python 3:
Comment interprétez-vous cela? Disons que vous avez un ensemble de 10 articles. Si chaque élément fait 100 octets chacun, quelle est la taille de la structure de données entière? L'ensemble est 736 lui-même car il a dimensionné une fois à 736 octets. Ensuite, vous ajoutez la taille des éléments, ce qui fait 1736 octets au total
Quelques mises en garde pour les définitions de fonction et de classe:
Notez que chaque définition de classe a une
__dict__
structure proxy (48 octets) pour les attr de classe. Chaque emplacement a un descripteur (comme aproperty
) dans la définition de classe.Les instances fendues commencent avec 48 octets sur leur premier élément et augmentent de 8 chacune supplémentaires. Seuls les objets fendus vides ont 16 octets, et une instance sans données n'a que très peu de sens.
De plus, chaque définition de fonction a des objets de code, peut-être des docstrings et d'autres attributs possibles, même a
__dict__
.Notez également que nous utilisons
sys.getsizeof()
parce que nous nous soucions de l'utilisation de l'espace marginal, qui inclut la surcharge de la récupération de place pour l'objet, à partir des documents :Notez également que le redimensionnement des listes (par exemple en les ajoutant de manière répétitive) les oblige à préallouer de l'espace, de la même manière que les ensembles et les dict. À partir du code source listobj.c :
Données historiques
Analyse Python 2.7, confirmée par
guppy.hpy
etsys.getsizeof
:Notez que les dictionnaires ( mais pas les ensembles ) ont une représentation plus 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 en mémoire où se trouve l'élément contenu. Les 4 octets sont à 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 maximale des caractères.
(Et pour en savoir plus sur les machines à sous, voir cette réponse )
Une fonction plus complète
Nous voulons une fonction qui recherche les éléments dans les listes, les tuples, les ensembles, les dict,
obj.__dict__
les, etobj.__slots__
, ainsi que d'autres choses auxquelles nous n'avons peut-être pas encore pensé.Nous voulons nous fier
gc.get_referents
à cette recherche car elle fonctionne au niveau C (ce qui la rend très rapide). L'inconvénient est que get_referents peut renvoyer des membres redondants, nous devons donc nous assurer de ne pas compter deux fois.Les classes, modules et fonctions sont des singletons - ils existent une fois dans la mémoire. Nous ne sommes pas tellement intéressés par leur taille, car nous ne pouvons pas faire grand-chose à leur sujet - ils font partie du programme. Nous éviterons donc de les compter s'ils sont référencés.
Nous allons utiliser une liste noire de types afin de ne pas inclure l'intégralité du programme dans notre nombre de tailles.
Pour contraster cela avec la fonction mise en liste blanche suivante, la plupart des objets savent comment se déplacer eux-mêmes à des fins de récupération de place (ce qui est approximativement ce que nous recherchons lorsque nous voulons savoir combien certains objets sont chers en mémoire. Cette fonctionnalité est utilisée par
gc.get_referents
.) Cependant, cette mesure va être beaucoup plus étendue que nous l’avions prévu si nous ne faisons pas attention.Par exemple, les fonctions en savent beaucoup sur les modules dans lesquels elles sont créées.
Un autre point de contraste est que les chaînes qui sont des clés dans les dictionnaires sont généralement internes afin qu'elles ne soient pas dupliquées. La vérification
id(key)
nous permettra également d'éviter de compter les doublons, ce que nous faisons dans la section suivante. La solution de liste noire ignore le comptage des clés qui sont des chaînes.Types sur liste blanche, visiteur récursif (ancienne implémentation)
Pour couvrir la plupart de ces types moi-même, au lieu de compter sur le module gc, j'ai écrit cette fonction récursive pour essayer d'estimer la taille de la plupart des objets Python, y compris la plupart des buildins, des types dans le module collections et des types personnalisés (à fentes et autres) .
Ce type de fonction donne un contrôle beaucoup plus fin sur les types que nous comptons pour l'utilisation de la mémoire, mais a le danger de laisser de côté les types:
Et je l'ai testé de façon plutôt nonchalante (je devrais ne pas le tester):
Cette implémentation décompose les définitions de classe et les définitions de fonctions parce que nous ne recherchons pas tous leurs attributs, mais comme ils ne devraient exister qu'une seule fois en mémoire pour le processus, leur taille n'a vraiment pas trop d'importance.
la source
Le module du package Pympler
asizeof
peut le faire.Utilisez comme suit:
Contrairement à
sys.getsizeof
cela, cela fonctionne pour vos objets auto-créés . Cela fonctionne même avec numpy.Comme mentionné ,
Et si vous avez besoin d'une autre vue sur les données en direct, Pympler
la source
org.apache.spark.util.SizeEstimator
peut être pertinentpympler
a la capacité de prendre en compte la taille de code exécutable des fonctions et autres objets appelables et objets de code.TypeError
exception: "L'objet 'NoneType' n'est pas appelable" chaque fois que mon objet personnalisé a un sous-objet dans son "arborescence" avec une valeurNone
. Existe-t-il une solution rapide à cela?Pour les tableaux numpy,
getsizeof
ne fonctionne pas - pour moi, il renvoie toujours 40 pour une raison quelconque:Puis (en ipython):
Heureusement, cependant:
la source
getsizeof()
ne vous donne que la taille de l'objet (l'en-tête du tableau), pas des données à l'intérieur. Idem pour les conteneurs python oùsys.getsizeof([1,2,4]) == sys.getsizeof([1,123**456,4]) == 48
, tandis quesys.getsizeof(123**456) = 436
getsizeof()
fonction ait été modifiée à un moment donné pour renvoyer la valeur attendue.Python 3.8 (T1 2019) changera certains des résultats de
sys.getsizeof
, comme annoncé ici par Raymond Hettinger:Cela vient après problème 33597 et le travail d' Inada Naoki (
methane
) autour de Compact PyGC_Head et PR 7043Voir commit d5c875b :
la source
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 la taille de la liste contenant les références aux entiers? (c.-à-d. liste uniquement, pas ce qui y est contenu), ou voulez-vous inclure les données réelles pointées, auquel cas vous devez traiter les références en double et comment empêcher le double comptage lorsque deux objets contiennent des références à le même objet.
Vous voudrez peut-être jeter un oeil à l'un des profileurs de mémoire python, comme pysizer pour voir s'ils répondent à vos besoins.
la source
Ayant moi-même rencontré ce problème plusieurs fois, j'ai rédigé 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:
https://github.com/bosswissam/pysize
Si la trame de fond vous intéresse, la voici
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.
la source
Voici un script rapide que j'ai écrit sur la base des réponses précédentes pour répertorier la taille de toutes les variables
la source
Vous pouvez sérialiser l'objet pour dériver une mesure étroitement liée à la taille de l'objet:
Si vous souhaitez mesurer des objets qui ne peuvent pas être décapés (par exemple à cause d'expressions lambda), cloudpickle peut être une solution.
la source
Utilisez sys.getsizeof () si vous NE souhaitez PAS inclure les tailles des objets liés (imbriqués).
Cependant, si vous voulez compter les sous-objets imbriqués dans des listes, des dict, des ensembles, des tuples - et généralement c'est ce que vous recherchez - utilisez la fonction récursive deep sizeof () comme indiqué ci-dessous:
Vous pouvez également trouver cette fonction dans la boîte à outils astucieuse , ainsi que de nombreuses autres lignes utiles:
https://github.com/mwojnars/nifty/blob/master/util.py
la source
Si vous n'avez pas besoin de la taille exacte de l'objet mais pour savoir approximativement sa taille, une façon rapide (et sale) consiste à laisser le programme s'exécuter, à dormir pendant une période prolongée et à vérifier l'utilisation de la mémoire (par ex. : Moniteur d'activité de Mac) par ce processus python particulier. Cela serait efficace lorsque vous essayez de trouver la taille d'un seul grand objet dans un processus python. Par exemple, j'ai récemment voulu vérifier l'utilisation de la mémoire d'une nouvelle structure de données et la comparer avec celle de la structure de données définie de Python. J'ai d'abord écrit les éléments (mots d'un grand livre du domaine public) dans un ensemble, puis j'ai vérifié la taille du processus, puis j'ai fait la même chose avec l'autre structure de données. J'ai découvert que le processus Python avec un ensemble prend deux fois plus de mémoire que la nouvelle structure de données. Encore une fois, vous ne voudriez pas t pouvoir dire exactement que la mémoire utilisée par le processus est égale à la taille de l'objet. Au fur et à mesure que la taille de l'objet devient grande, cela devient proche car la mémoire consommée par le reste du processus devient négligeable par rapport à la taille de l'objet que vous essayez de surveiller.
la source
Vous pouvez utiliser getSizeof () comme mentionné ci-dessous pour déterminer la taille d'un objet
la source
J'utilise cette astuce ... Peut ne pas être précis sur les petits objets, mais je pense que c'est beaucoup plus précis pour un objet complexe (comme la surface pygame) plutôt que sys.getsizeof ()
Sur mes fenêtres 10, python 3.7.3, la sortie est:
la source