4

私はいじっていましsys.getsizeofたが、リストと配列にたどり着いたときは少し驚きました:

>>> from sys import getsizeof as sizeof
>>> list_ = range(10**6)
>>> sizeof(list_)
8000072

配列との比較:

>>> from array import array
>>> array_ = array('i', range(10**6))
>>> sizeof(array_)
56

整数のリストのサイズは、そのすべての要素のサイズの 1/3 になる傾向があるため、それらを保持することはできません。

>>> sizeof(10**8)
24
>>> for i in xrange(0,9):
...  round(sizeof(range(10**i)) / ((10**i) * 24.0), 4), "10**%s elements" % (i)
... 
(3.3333, '10**0 elements')
(0.6333, '10**1 elements')
(0.3633, '10**2 elements')
(0.3363, '10**3 elements')
(0.3336, '10**4 elements')
(0.3334, '10**5 elements')
(0.3333, '10**6 elements')
(0.3333, '10**7 elements')
(0.3333, '10**8 elements')

list大きいがすべての要素ほど大きくなく、array非常に小さいというこの動作の原因は何ですか?

4

2 に答える 2

0

getsizeof 関数は、リストのようなコンテナー内のアイテムのサイズを測定しません。個々の要素をすべて追加する必要があります。

これを行うためのレシピを次に示します。

ここに再現:

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)

そのレシピを使用してこれをリストで実行すると、違いがわかります。

>>> alist=[[2**99]*10, 'a string', {'one':1}]
>>> print('getsizeof: {}, total_size: {}'.format(getsizeof(alist), total_size(alist)))
getsizeof: 96, total_size: 721
于 2013-08-12T11:37:11.083 に答える