web-dev-qa-db-fra.com

Comment connaître la taille en octets de python comme les tableaux et les dictionnaires? - La manière simple

Je cherchais un moyen simple de connaître la taille en octets des tableaux et des objets de dictionnaires, comme

[ [1,2,3], [4,5,6] ] or { 1:{2:2} }

De nombreux sujets disent d'utiliser pylab, par exemple:

from pylab import *

A = array( [ [1,2,3], [4,5,6] ] )
A.nbytes
24

Mais qu'en est-il des dictionnaires? J'ai vu beaucoup de réponses proposant d'utiliser pysize ou heapy. Une réponse simple est donnée par Torsten Marek dans ce lien: Quel Python est recommandé? , mais je n'ai pas d'interprétation claire sur la sortie car le nombre d'octets ne correspondait pas.

Pysize semble être plus compliqué et je n'ai pas encore d'idée claire sur la façon de l'utiliser.

Compte tenu de la simplicité du calcul de la taille que je veux effectuer (pas de classes ni de structures complexes), une idée d'un moyen facile d'obtenir une estimation approximative de l'utilisation de la mémoire de ce type d'objets?

Sincères amitiés.

40
crandrades

Il y a:

>>> import sys
>>> sys.getsizeof([1,2, 3])
96
>>> a = []
>>> sys.getsizeof(a)
72
>>> a = [1]
>>> sys.getsizeof(a)
80

Mais je ne dirais pas que c'est aussi fiable, car Python a des frais généraux pour chaque objet, et il y a des objets qui ne contiennent que des références à d'autres objets, donc ce n'est pas tout à fait la même chose qu'en C et autres langues.

Lisez les documents sur sys.getsizeof et allez-y, je suppose.

49
Jon Clements

un peu tard pour la fête, mais un moyen facile d'obtenir la taille du dict est de le décaper en premier.

L'utilisation de sys.getsizeof sur python (dictionnaire compris) peut ne pas être exacte car elle ne compte pas les objets référencés.

La façon de le gérer consiste à le sérialiser en une chaîne et à utiliser sys.getsizeof sur la chaîne. Le résultat sera beaucoup plus proche de ce que vous voulez.

import cPickle

mydict = {'key1':'some long string, 'key2':[some, list], 'key3': whatever other data}

faire sys.getsizeof (mydict) n'est pas exact donc, décapez-le d'abord

mydict_as_string = cPickle.dumps(mydict)

maintenant, nous pouvons savoir combien d'espace il faut

print sys.getsizeof(mydict_as_string)
27
Denis Kanygin

Aucune des réponses ici n'est vraiment générique.

La solution suivante fonctionnera avec n'importe quel type d'objet de manière récursive, sans avoir besoin d'une implémentation récursive coûteuse:

import gc
import sys

def get_obj_size(obj):
    marked = {id(obj)}
    obj_q = [obj]
    sz = 0

    while obj_q:
        sz += sum(map(sys.getsizeof, obj_q))

        # Lookup all the object referred to by the object in obj_q.
        # See: https://docs.python.org/3.7/library/gc.html#gc.get_referents
        all_refr = ((id(o), o) for o in gc.get_referents(*obj_q))

        # Filter object that are already marked.
        # Using dict notation will prevent repeated objects.
        new_refr = {o_id: o for o_id, o in all_refr if o_id not in marked and not isinstance(o, type)}

        # The new obj_q will be the ones that were not marked,
        # and we will update marked with their ids so we will
        # not traverse them again.
        obj_q = new_refr.values()
        marked.update(new_refr.keys())

    return sz

Par exemple:

>>> import numpy as np
>>> x = np.random.Rand(1024).astype(np.float64)
>>> y = np.random.Rand(1024).astype(np.float64)
>>> a = {'x': x, 'y': y}
>>> get_obj_size(a)
16816

Voir mon référentiel pour plus d'informations, ou installez simplement mon package ( objsize ):

$ pip install objsize

Ensuite:

>>> from objsize import get_deep_size
>>> get_deep_size(a)
16816
17
Liran Funaro

Utilisez cette recette, tirée d'ici:

http://code.activestate.com/recipes/577504-compute-memory-footprint-of-an-object-and-its-cont/

from __future__ import print_function
from sys import getsizeof, stderr
from itertools import chain
from collections import deque
try:
    from reprlib import repr
except ImportError:
    pass

def total_size(o, handlers={}, verbose=False):
    """ Returns the approximate memory footprint an object and all of its contents.

    Automatically finds the contents of the following builtin containers and
    their subclasses:  Tuple, list, deque, dict, set and frozenset.
    To search other containers, add handlers to iterate over their contents:

        handlers = {SomeContainerClass: iter,
                    OtherContainerClass: OtherContainerClass.get_elements}

    """
    dict_handler = lambda d: chain.from_iterable(d.items())
    all_handlers = {Tuple: iter,
                    list: iter,
                    deque: iter,
                    dict: dict_handler,
                    set: iter,
                    frozenset: iter,
                   }
    all_handlers.update(handlers)     # user handlers take precedence
    seen = set()                      # track which object id's have already been seen
    default_size = getsizeof(0)       # estimate sizeof object without __sizeof__

    def sizeof(o):
        if id(o) in seen:       # do not double count the same object
            return 0
        seen.add(id(o))
        s = getsizeof(o, default_size)

        if verbose:
            print(s, type(o), repr(o), file=stderr)

        for typ, handler in all_handlers.items():
            if isinstance(o, typ):
                s += sum(map(sizeof, handler(o)))
                break
        return s

    return sizeof(o)


##### Example call #####

if __== '__main__':
    d = dict(a=1, b=2, c=3, d=[4,5,6,7], e='a string of chars')
    print(total_size(d, verbose=True))
12
Oren