Pythonでプログラミングするとき、既知の数の項目が入力されるリスト用にメモリを予約して、リストの作成中にリストが何度も再割り当てされないようにすることはできますか?私はPythonリストタイプのドキュメントを調べましたが、これを行うように見えるものは何も見つかりませんでした。しかし、このタイプのリスト作成は私のコードのいくつかのホットスポットに現れます、できるだけ効率的にしたいです。
編集:また、Pythonのような言語でこのようなことをするのも理にかなっていますか?私はかなり経験豊富なプログラマーですが、Pythonの初心者であり、そのやり方を実感しています。そうではありません。Python内部的に割り当てallオブジェクトを個別のヒープスペースに配置し、割り当てを最小化しようとする目的に反するか、int、floatなどのプリミティブをリストに直接保存していますか?
ここに4つのバリアントがあります:
python -mtimeit -s"N=10**6" "a = []; app = a.append;"\
"for i in xrange(N): app(i);"
10 loops, best of 3: 390 msec per loop
python -mtimeit -s"N=10**6" "a = [None]*N; app = a.append;"\
"for i in xrange(N): a[i] = i"
10 loops, best of 3: 245 msec per loop
python -mtimeit -s"from array import array; N=10**6" "a = array('i', [0]*N)"\
"for i in xrange(N):" " a[i] = i"
10 loops, best of 3: 541 msec per loop
python -mtimeit -s"from numpy import zeros; N=10**6" "a = zeros(N,dtype='i')"\
"for i in xrange(N):" " a[i] = i"
10 loops, best of 3: 353 msec per loop
[None]*N
が最速で、array.array
はこの場合最も遅いです。
次のようにして、既知の長さのリストを作成できます。
>>> [None] * known_number
これをみて:
_In [7]: %timeit array.array('f', [0.0]*4000*1000)
1 loops, best of 3: 306 ms per loop
In [8]: %timeit array.array('f', [0.0])*4000*1000
100 loops, best of 3: 5.96 ms per loop
In [11]: %timeit np.zeros(4000*1000, dtype='f')
100 loops, best of 3: 6.04 ms per loop
In [9]: %timeit [0.0]*4000*1000
10 loops, best of 3: 32.4 ms per loop
_
そのため、array.array('f', [0.0]*N)
を使用しないでください。array.array('f', [0.0])*N
または_numpy.zeros
_を使用してください。
ほとんどの日常的なコードでは、そのような最適化は必要ありません。
ただし、リストの効率が問題になる場合、最初にすべきことは、一般的なリストを array
module の型付きリストに置き換えることです。
400万個の浮動小数点数のリストを作成する方法は次のとおりです。
import array
lst = array.array('f', [0.0]*4000*1000)
Python=で数値を効率的に操作したい場合は、NumPy( http://numpy.scipy.org/ )をご覧ください。) Pythonを使いながら非常に高速です。
NumPyであなたが求めていることを行うには、次のようなことをします
import numpy as np
myarray = np.zeros(4000)
これにより、ゼロに初期化された浮動小数点数の配列が得られます。次に、配列全体を単一の因子で乗算したり、他の配列やその他のもの(これまでに使用したことがある場合は、Matlabのようなもの)で乗算したり、非常に高速な処理を実行できます(実際の作業のほとんどは、 NumPyライブラリの高度に最適化されたC部分)。
それが数の配列でない場合は、Pythonで必要なことを行う方法を見つけることができないでしょう。 Pythonオブジェクトのリストは、内部のオブジェクトへのポイントのリストです(とにかく、私はPython internals)の専門家ではないので)メンバーを作成するときは、メンバーを割り当てます。
Pythonでは、すべてのオブジェクトがヒープに割り当てられます。
しかしPythonは特別なメモリアロケータを使用するため、新しいオブジェクトが必要になるたびにmalloc
が呼び出されることはありません。
また、キャッシュされる小さな整数(など)に対するいくつかの最適化があります。ただし、タイプと方法は実装に依存します。
python3の場合:
import timeit
from numpy import zeros
from array import array
def func1():
N=10**6
a = []
app = a.append
for i in range(N):
app(i)
def func2():
N=10**6
a = [None]*N
app = a.append
for i in range(N):
a[i] = i
def func3():
N=10**6
a = array('i', [0]*N)
for i in range(N):
a[i] = i
def func4():
N=10**6
a = zeros(N,dtype='i')
for i in range(N):
a[i] = i
start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)
start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)
start_time = timeit.default_timer()
func3()
print(timeit.default_timer() - start_time)
start_time = timeit.default_timer()
func4()
print(timeit.default_timer() - start_time)
結果:
0.1655518
0.10920069999999998
0.1935983
0.15213890000000002