1

80000個のリストで構成されるPythonリストがあります。これらの内部リストのそれぞれは、多かれ少なかれこの形式を持っています:

["012345", "MYNAME" "Mon", "A", 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20]

80000個のリストで構成されるこのリストが消費するメモリの概算を教えてください。

そして、Pythonで非常に大きなリストを使用して操作することは一般的/ OKですか?私が行う操作のほとんどは、リスト内包法を使用してこのリストからデータを抽出することです。

実際、私が学びたいのは、Pythonは、リスト内包法を使用してその大きなリストからデータを抽出するのに十分な速度であるということです。スクリプトを高速にしたい

4

5 に答える 5

3
In [39]: lis=["012345", "MYNAME" "Mon", "A", 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
     20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20]

In [40]: k=[lis[:] for _ in xrange(80000)]

In [41]: k.__sizeof__()
Out[41]: 325664

In [42]: sys.getsizeof(k)  #after gc_head
Out[42]: 325676

その中のコードによると、オブジェクトのサイズを取得するためにメソッドをsysmodule.c呼び出すように見えます。__sizeof__

   837   method = _PyObject_LookupSpecial(o, &PyId___sizeof__);   
   838     if (method == NULL) {
   839         if (!PyErr_Occurred())
   840             PyErr_Format(PyExc_TypeError,
   841                          "Type %.100s doesn't define __sizeof__",
   842                          Py_TYPE(o)->tp_name);
   843     }
   844     else {
   845         res = PyObject_CallFunctionObjArgs(method, NULL);
   846         Py_DECREF(method);
   847     }

gc次に、それにオーバーヘッドを追加します。

   860     /* add gc_head size */
   861     if (PyObject_IS_GC(o)) {
   862         PyObject *tmp = res;
   863         res = PyNumber_Add(tmp, gc_head_size);
   864         Py_DECREF(tmp);
   865     }
   866     return res;
   867 }

ドキュメントrecursive sizeof recipeで提案されているように、各コンテナのサイズを再帰的に計算することもできます。

In [17]: total_size(k)  #from recursive sizeof recipe
Out[17]: 13125767

In [18]: sum(y.__sizeof__() for x in k for y in x)
Out[18]: 34160000
于 2013-01-21T21:18:02.230 に答える
3

32ビットPython2.7.3を使用している私のマシンでは、質問の正確なリストの80Kコピーを含むリストは約10MBかかります。これは、2つの他の点では同一のインタプリタのメモリフットプリントを比較することによって測定されました。1つはリストあり、もう1つはリストなしです。

でサイズを測定しようとしましsys.getsizeof()たが、明らかに間違った結果が返されました。

>>> l=[["012345", "MYNAME" "Mon", "A", 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20] for i in range(80000)]
>>> sys.getsizeof(l)
325680
于 2013-01-21T21:18:14.257 に答える
1

現在の(rev 13)コードをPythonオブジェクトのサイズ(改訂)レシピに適用し、というモジュールに配置しsizeofてから、サンプルリストに適用すると、次のようになります(32ビットPython 2.7.3を使用)。

from sizeof import asizeof  # from http://code.activestate.com/recipes/546530

MB = 1024*1024
COPIES = 80000
lis=["012345", "MYNAME" "Mon", "A", 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
     20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20]

lis_size = asizeof(lis)
print 'asizeof(lis): {} bytes'.format(lis_size)
list_of_lis_size = asizeof([lis[:] for _ in xrange(COPIES)])
print 'asizeof(list of {:,d} copies of lis): {:,d} bytes ({:.2f} MB)'.format(
                         COPIES, list_of_lis_size, list_of_lis_size/float(MB))
asizeof(lis): 272 bytes
asizeof(list of 80,000 copies of lis): 13,765,784 bytes (13.13 MB)
于 2013-01-21T22:55:07.603 に答える
1

sys.getsizeof :(オブジェクト、デフォルト)
││getsizeof(オブジェクト、デフォルト)->int││<br>││オブジェクト
のサイズをバイト単位で返します。

コード

>> import sys
>> sys.getsizeof(["012345", "MYNAME" "Mon", "A", 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20])
>> 160

160リストのバイトを返します。これに約80,000または12.8MBを掛けます。(Python 2.7.2、Python 3.2を搭載した32ビットマシン)

于 2013-01-21T21:20:55.967 に答える
0

インタプリタとの次の相互作用に注意してください。

>>> import sys
>>> array = ['this', 'is', 'a', 'string', 'array']
>>> sys.getsizeof(array)
56
>>> list(map(sys.getsizeof, array))
[29, 27, 26, 31, 30]
>>> sys.getsizeof(array) + sum(map(sys.getsizeof, array))
199
>>> 

この特定の場合の答えはsys.getsizeof(array) + sum(map(sys.getsizeof, array))、文字列のリストのサイズを見つけるために使用することです。ただし、以下は、オブジェクトコンテナ、クラス、および__slots__の使用法を考慮したより完全な実装です。

import sys

def sizeof(obj):
    return _sizeof(obj, set())

def _sizeof(obj, memo):
    # Add this object's size just once.
    location = id(obj)
    if location in memo:
        return 0
    memo.add(location)
    total = sys.getsizeof(obj)
    # Look for any class instance data.
    try:
        obj = vars(obj)
    except TypeError:
        pass
    # Handle containers holding objects.
    if isinstance(obj, (tuple, list, frozenset, set)):
        for item in obj:
            total += _sizeof(item, memo)
    # Handle the two-sided nature of dicts.
    elif isinstance(obj, dict):
        for key, value in dict.items():
            total += _sizeof(key, memo) + _sizeof(value, memo)
    # Handle class instances using __slots__.
    elif hasattr(obj, '__slots__'):
        for key, value in ((name, getattr(obj, name))
            for name in obj.__slots__ if hasattr(obj, name)):
            total += _sizeof(key, memo) + _sizeof(value, memo)
    return total

編集:

しばらくしてこの問題に取り組んだ後、次の代替案が考案されました。無限イテレータではうまく機能しないことに注意してください。このコードは、分析の準備ができている静的データ構造に最適です。

import sys

sizeof = lambda obj: sum(map(sys.getsizeof, explore(obj, set())))

def explore(obj, memo):
    loc = id(obj)
    if loc not in memo:
        memo.add(loc)
        yield obj
        # Handle instances with slots.
        try:
            slots = obj.__slots__
        except AttributeError:
            pass
        else:
            for name in slots:
                try:
                    attr = getattr(obj, name)
                except AttributeError:
                    pass
                else:
                    yield from explore(attr, memo)
        # Handle instances with dict.
        try:
            attrs = obj.__dict__
        except AttributeError:
            pass
        else:
            yield from explore(attrs, memo)
        # Handle dicts or iterables.
        for name in 'keys', 'values', '__iter__':
            try:
                attr = getattr(obj, name)
            except AttributeError:
                pass
            else:
                for item in attr():
                    yield from explore(item, memo)
于 2013-01-21T22:48:26.297 に答える