web-dev-qa-db-ja.com

Pythonのリスト用にメモリを予約しますか?

Pythonでプログラミングするとき、既知の数の項目が入力されるリスト用にメモリを予約して、リストの作成中にリストが何度も再割り当てされないようにすることはできますか?私はPythonリストタイプのドキュメントを調べましたが、これを行うように見えるものは何も見つかりませんでした。しかし、このタイプのリスト作成は私のコードのいくつかのホットスポットに現れます、できるだけ効率的にしたいです。

編集:また、Pythonのような言語でこのようなことをするのも理にかなっていますか?私はかなり経験豊富なプログラマーですが、Pythonの初心者であり、そのやり方を実感しています。そうではありません。Python内部的に割り当てallオブジェクトを個別のヒープスペースに配置し、割り当てを最小化しようとする目的に反するか、int、floatなどのプリミティブをリストに直接保存していますか?

44
dsimcha

ここに4つのバリアントがあります:

  • 増分リストの作成
  • 「事前割り当て」リスト
  • array.array()
  • numpy.zeros()

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はこの場合最も遅いです。

34
jfs

次のようにして、既知の長さのリストを作成できます。

>>> [None] * known_number
13
SilentGhost

これをみて:

_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_を使用してください。

8
Mikhail Korobov

ほとんどの日常的なコードでは、そのような最適化は必要ありません。

ただし、リストの効率が問題になる場合、最初にすべきことは、一般的なリストを array module の型付きリストに置き換えることです。

400万個の浮動小数点数のリストを作成する方法は次のとおりです。

import array
lst = array.array('f', [0.0]*4000*1000)
5

Python=で数値を効率的に操作したい場合は、NumPy( http://numpy.scipy.org/ )をご覧ください。) Pythonを使いながら非常に高速です。

NumPyであなたが求めていることを行うには、次のようなことをします

import numpy as np
myarray = np.zeros(4000)

これにより、ゼロに初期化された浮動小数点数の配列が得られます。次に、配列全体を単一の因子で乗算したり、他の配列やその他のもの(これまでに使用したことがある場合は、Matlabのようなもの)で乗算したり、非常に高速な処理を実行できます(実際の作業のほとんどは、 NumPyライブラリの高度に最適化されたC部分)。

それが数の配列でない場合は、Pythonで必要なことを行う方法を見つけることができないでしょう。 Pythonオブジェクトのリストは、内部のオブジェクトへのポイントのリストです(とにかく、私はPython internals)の専門家ではないので)メンバーを作成するときは、メンバーを割り当てます。

4
Thomas Parslow

Pythonでは、すべてのオブジェクトがヒープに割り当てられます。
しかしPythonは特別なメモリアロケータを使用するため、新しいオブジェクトが必要になるたびにmallocが呼び出されることはありません。
また、キャッシュされる小さな整数(など)に対するいくつかの最適化があります。ただし、タイプと方法は実装に依存します。

2

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
  1. append()
  2. [なし] * N
  3. モジュール配列の使用
  4. モジュールnumpyを使用する
0
Vitaly Fadeev