2011-02-09 13 views
18

ここでは、スタックオーバーフローに関するコメントを読んで、リストを変更するときにスライスの割り当てを行う方が効率的です。後者は、新しいリストを作成し、その新しいリストにaを再バインド前者は、既存のリスト内の要素を置換するため、例えば、Pythonスライスの代入メモリの使用

a[:] = [i + 6 for i in a] 

は残し、

a = [i + 6 for i in a] 

より効率的でより多くのメモリであるべきです古いaがガベージコレクションされるまでメモリに残っています。スピードのための2つのベンチマーク、後者はやや高速です:

私が期待するものである
$ python -mtimeit -s 'a = [1, 2, 3]' 'a[:] = [i + 6 for i in a]' 
1000000 loops, best of 3: 1.53 usec per loop 
$ python -mtimeit -s 'a = [1, 2, 3]' 'a = [i + 6 for i in a]' 
1000000 loops, best of 3: 1.37 usec per loop 

は、変数を再バインドするよう、リスト内の要素を交換するよりも高速である必要があります。しかし、私はメモリ使用量の主張をサポートする正式な文書を見つけることができません、そして、私はそれをベンチマークする方法がわかりません。

メモリ使用量の主張は私にとっては理にかなっています。しかし、私は以前の方法では、前者の方法では、リストの理解から新しいリストを作成し、の値にコピーして、aに値をコピーし、ガベージコレクションされています。そうであれば、前者の方法は同じ量のメモリを使用し、同時に遅くする。

2人の方法のどちらがより効率的なメモリであるかをベンチマークや公式の文書で明示的に示すことはできますか?

ありがとうございます。

+1

パフォーマンス面で検討する価値はあるかもしれませんが、Class1からClass2への参照を渡す実用的なケース(大きなプログラムでは)に遭遇する可能性が高いと思います。最初の例では、スライス割り当てを使用してClass1のリストを変更すると、Class2の参照が保持されます。 2番目のインスタンスでは、Class1のリストを変更すると、Class2はもはや有効ではないリストへの参照を保持します。 – Brandon

+0

@Brandon:それも当てはまりますが、私はおそらく私の質問でその区別を述べておくべきでした。あなたのご意見ありがとうございます。 –

答えて

40

ライン

a[:] = [i + 6 for i in a] 

は、任意のメモリを保存しないでしょう。 language documentationに述べたようにPythonは、最初の右側を評価し:

代入文は、式リストを評価する(後者はタプルを得、これは単一の式、またはコンマ区切りのリストであってもよいことに注意してください)結果として得られる単一のオブジェクトを左から右へとそれぞれのターゲットリストに割り当てます。

手元にある結果オブジェクトは新しいリストになり、ターゲットリスト内の単一のターゲットはa[:]になります。

我々はジェネレータ式でリストの内包を置き換えることができます:

a[:] = (i + 6 for i in a) 

、右側ではなく、リストの発電機に評価されます。ベンチマークは、これはまだそうジェネレータ式は、実際に任意のメモリを節約んナイーブ

a = [i + 6 for i in a] 

よりも低速であることを示していますか?一見すると、あなたはそう思うかもしれません。しかし、source code of the function list_ass_slice()に掘り下げてみると、そうではないことがわかります。ライン

v_as_SF = PySequence_Fast(v, "can only assign an iterable"); 

は、古いリストにコピーされた最初のタプルに反復可能(この場合は発電機)を変換するPySequence_Fast()を使用します。タプルはリストと同じ量のメモリを使用するため、ジェネレータ式を使用するのは基本的にリスト内包を使用する場合と同じです。最後のコピー中に、元のリストの項目が再利用されます。

道徳的な考え方は、最も単純なアプローチが最も良いアプローチであると思われます。

+4

未熟な(メモリ)オプティマイザを無謀に粉砕するための+1。 – delnan

+0

詳細で洞察に満ちた答えをありがとう!上記のコメント担当者にお答えすると、500万要素のリストを扱っていて、コピーしていない場合とコピーしない場合の選択肢がある場合、早すぎる最適化ではない可能性があることを付け加えたいと思います。 :) –

+1

@Mitch:もし5百万のエントリがあれば、おそらく、より良い結果が得られます。 PythonリストよりもNumPy配列です。 –

関連する問題