web-dev-qa-db-ja.com

list()はリスト内包表記よりも多くのメモリを使用します

だから私はlistオブジェクトで遊んでいて、listlist()で作成された場合、リストの理解よりも多くのメモリを使用するという奇妙なことを見つけましたか?私はPython 3.5.2を使用しています

_In [1]: import sys
In [2]: a = list(range(100))
In [3]: sys.getsizeof(a)
Out[3]: 1008
In [4]: b = [i for i in range(100)]
In [5]: sys.getsizeof(b)
Out[5]: 912
In [6]: type(a) == type(b)
Out[6]: True
In [7]: a == b
Out[7]: True
In [8]: sys.getsizeof(list(b))
Out[8]: 1008
_

docs から:

リストはいくつかの方法で作成できます:

  • 空のリストを示すために角括弧のペアを使用する:_[]_
  • 角括弧を使用して、コンマで項目を区切ります:_[a]_、_[a, b, c]_
  • リスト内包表記の使用:_[x for x in iterable]_
  • 型コンストラクターの使用:list()またはlist(iterable)

しかし、list()を使用すると、より多くのメモリを使用するようです。

そして、listが大きいほど、ギャップは大きくなります。

Difference in memory

なぜこれが起こるのですか?

更新#1

Python 3.6.0b2でテスト:

_Python 3.6.0b2 (default, Oct 11 2016, 11:52:53) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getsizeof(list(range(100)))
1008
>>> sys.getsizeof([i for i in range(100)])
912
_

更新#2

Python 2.7.12:

_Python 2.7.12 (default, Jul  1 2016, 15:12:24) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getsizeof(list(xrange(100)))
1016
>>> sys.getsizeof([i for i in xrange(100)])
920
_
78
vishes_shell

すばらしいPythonを理解するのを手伝ってくれてありがとう。

そんなに大掛かりな質問をしたくはありません(なぜ答えを投稿しているのか)、自分の考えを見せて共有したいだけです。

@ ReutSharabani のように正しく記述されています: "list()は決定的にリストサイズを決定します"。そのグラフから見ることができます。

graph of sizes

appendを使用するとき、またはリストの内包表記を使用するときは、何らかのポイントに達すると常に何らかの境界が広がります。 list()を使用すると、ほぼ同じ境界がありますが、それらは浮いています。

[〜#〜] update [〜#〜]

@ ReutSharabani@ tavo@ SvenFestersen に感謝

要約すると、list()はリストのサイズに応じてメモリを事前に割り当てますが、リストの内包表記はそれを行うことができません(.append()のように、必要に応じて追加のメモリを要求します)。 list()がより多くのメモリを保存する理由です。

list()事前割り当てメモリを示すもう1つのグラフ。そのため、緑色の線はlist(range(830))が要素ごとに追加され、しばらくの間メモリが変化しないことを示しています。

list() preallocates memory

更新2

@Barmarが以下のコメントで述べたように、list()はリストの内包表記よりも速くなければならないので、長さlistからnumber=1000から4**0までの4**10timeit()を実行しました。

time measurements

28
vishes_shell