2013-09-01 13 views
7

これはささいなことかもしれませんが、わかりませんが、私はグーグルで遊んでみましたが、説得力のある答えは見つかりませんでした。なぜ空のdictのサイズはPythonの空でないdictのサイズと同じですか?

>>> sys.getsizeof({}) 
140 
>>> sys.getsizeof({'Hello':'World'}) 
140 
>>> 
>>> yet_another_dict = {} 
>>> for i in xrange(5000): 
     yet_another_dict[i] = i**2 

>>> 
>>> sys.getsizeof(yet_another_dict) 
98444 

どうすればわかりますか? 空のディクテーションが空でないディクテーションと同じサイズの理由は何ですか?

+1

ディクテーションで動画を視聴する必要があります:[The mighty dictionary](http://blip.tv/pycon-us-videos-2009-2010-2011/pycon-2010-the-mighty-dictionary-55-3352147) –

答えて

9

そのための2つの理由があります。それのサイズが何のオブジェクトのサイズと相関しているので、

  1. 辞書は、それが含まれている、オブジェクトへの参照ではなく、オブジェクト自体を保持していませんしかし、辞書には参照の数(項目)が含まれています。

  2. さらに重要なことに、辞書はチャンク内の参照のメモリを事前に割り当てます。したがって、辞書を作成したときには、すでに最初のnの参照用のメモリーが事前に割り当てられています。メモリをいっぱいにすると、新しいチャンクがあらかじめ割り当てられます。

次のコードを実行すると、動作が確認できます。

出力し
d = {} 
size = sys.getsizeof(d) 
print size 
i = 0 
j = 0 
while i < 3: 
    d[j] = j 
    j += 1 
    new_size = sys.getsizeof(d) 
    if size != new_size: 
     print new_size 
     size = new_size 
     i += 1 

:私のマシン上で

280 
1048 
3352 
12568 

を、これはアーキテクチャ(32ビット、64ビット)に依存します。

7

CPythonの辞書は、辞書オブジェクト自体に少量のキースペースを直接割り当てます(バージョンとコンパイルオプションによっては4〜8個のエントリ)。 dictobject.hから:

/* PyDict_MINSIZE is the minimum size of a dictionary. This many slots are 
* allocated directly in the dict object (in the ma_smalltable member). 
* It must be a power of 2, and at least 4. 8 allows dicts with no more 
* than 5 active entries to live in ma_smalltable (and so avoid an 
* additional malloc); instrumentation suggested this suffices for the 
* majority of dicts (consisting mostly of usually-small instance dicts and 
* usually-small dicts created to pass keyword arguments). 
*/ 
#ifndef Py_LIMITED_API 
#define PyDict_MINSIZE 8 

注意CPythonのも成長している辞書のための頻繁な再配分を避けるために、バッチで辞書のサイズを変更していること。 dictobject.cから:

/* If we added a key, we can safely resize. Otherwise just return! 
* If fill >= 2/3 size, adjust size. Normally, this doubles or 
* quaduples the size, but it's also possible for the dict to shrink 
* (if ma_fill is much larger than ma_used, meaning a lot of dict 
* keys have been * deleted). 
* 
* Quadrupling the size improves average dictionary sparseness 
* (reducing collisions) at the cost of some memory and iteration 
* speed (which loops over every possible entry). It also halves 
* the number of expensive resize operations in a growing dictionary. 
* 
* Very large dictionaries (over 50K items) use doubling instead. 
* This may help applications with severe memory constraints. 
*/ 
if (!(mp->ma_used > n_used && mp->ma_fill*3 >= (mp->ma_mask+1)*2)) 
    return 0; 
return dictresize(mp, (mp->ma_used > 50000 ? 2 : 4) * mp->ma_used); 
関連する問題