1 次元配列を作成する場合は、それをリストとして実装するか、標準ライブラリの「配列」モジュールを使用できます。私は常に1次元配列にリストを使用してきました。
代わりに配列モジュールを使用する理由または状況は何ですか?
パフォーマンスとメモリの最適化のためですか、それとも明らかな何かが欠けていますか?
基本的に、Pythonリストは非常に柔軟性があり、完全に異種の任意のデータを保持でき、償却された一定時間で非常に効率的に追加できます。リストを時間効率よく、手間をかけずに縮小および拡大する必要がある場合は、それらが最適な方法です。ただし、単純なC型(または)で表すことができるデータの場合でも、リスト内の各項目で個別のPythonオブジェクトを作成する必要があるため、C配列よりもはるかに多くのスペースを使用します。float
uint64_t
一方、このarray.array
タイプは、C配列の単なる薄いラッパーです。同種のデータ(つまり、すべて同じタイプ)のみを保持できるためsizeof(one object) * length
、メモリのバイトのみを使用します。ioctl
ほとんどの場合、C配列を拡張機能またはシステムコール(たとえば、fctnl
)に公開する必要がある場合に使用する必要があります。
array.array
Python 2.x()で可変文字列を表すための合理的な方法でもありarray('B', bytes)
ます。ただし、Python 2.6以降および3.xは、可変バイト文字列をとして提供しbytearray
ます。
ただし、数値データの同種配列で数学を実行する場合は、複雑な多次元配列での操作を自動的にベクトル化できるNumPyを使用することをお勧めします。
長い話を短くするために:数学を行う以外array.array
の理由でデータの同種のC配列が必要な場合に役立ちます。
ほとんどの場合、通常のリストが正しい選択です。arrays モジュールは、C 配列の薄いラッパーに似ており、ビルドの一部ではない、signed/unsigned short や double などのより C に似た型にアクセスできる、一種の厳密に型指定されたコンテナー ( docsを参照) を提供します。 -in タイプ。arrays モジュールは、本当に必要な場合にのみ使用してください。それ以外の場合はすべて、リストを使用してください。
配列モジュールは、なぜそれを使用するのかわからない場合は、おそらく必要のないものの 1 つです (そして、私が見下すような方法でそれを言おうとしているわけではないことに注意してください!) . ほとんどの場合、array モジュールは C コードとのインターフェースに使用されます。パフォーマンスに関する質問に対して、より直接的な回答を提供するには:
用途によっては、配列はリストよりも効率的です。変更されないことがわかっている配列を割り当てる必要がある場合は、配列の方が高速でメモリ使用量が少なくて済みます。GvR には、配列モジュールが勝者であることが判明した最適化の逸話があります (長い間読んでいますが、それだけの価値があります)。
一方、リストが配列よりも多くのメモリを消費する理由の一部は、割り当てられたすべての要素が使用されると、Python がいくつかの余分な要素を割り当てるためです。これは、リストへのアイテムの追加がより高速であることを意味します。したがって、アイテムを追加する予定がある場合は、リストが最適です。
TL;DR 例外的な最適化が必要な場合、または C コードとのインターフェイスが必要な場合 (およびpyrexを使用できない場合) にのみ、配列を使用します。
私の理解では、配列はより効率的に格納されます (つまり、メモリの連続ブロックと Python オブジェクトへのポインタとして)。ただし、パフォーマンス上の利点については認識していません。さらに、配列では同じ型のプリミティブを格納する必要がありますが、リストは何でも格納できます。
標準ライブラリ配列は、intのリストを文字列に変換してWaveファイルなどに書き込むなどのバイナリI/Oに役立ちます。とはいえ、多くの人がすでに指摘しているように、実際の作業を行う場合は、NumPyの使用を検討する必要があります。
配列を使用する場合は、より柔軟な配列を提供する numpy または scipy パッケージを検討してください。
パフォーマンスに関しては、Python のリスト、配列、numpy 配列を比較した数値をいくつか示します (すべて 2017 Macbook Pro で Python 3.7 を使用)。最終結果は、これらの操作では python リストが最速です。
# Python list with append()
np.mean(timeit.repeat(setup="a = []", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.054 +/- 0.025 msec
# Python array with append()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.104 +/- 0.025 msec
# Numpy array with append()
np.mean(timeit.repeat(setup="import numpy as np; a = np.array([])", stmt="np.append(a, [1.0])", number=1000, repeat=5000)) * 1000
# 5.183 +/- 0.950 msec
# Python list using +=
np.mean(timeit.repeat(setup="a = []", stmt="a += [1.0]", number=1000, repeat=5000)) * 1000
# 0.062 +/- 0.021 msec
# Python array using +=
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a += array.array('f', [1.0]) ", number=1000, repeat=5000)) * 1000
# 0.289 +/- 0.043 msec
# Python list using extend()
np.mean(timeit.repeat(setup="a = []", stmt="a.extend([1.0])", number=1000, repeat=5000)) * 1000
# 0.083 +/- 0.020 msec
# Python array using extend()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.extend([1.0]) ", number=1000, repeat=5000)) * 1000
# 0.169 +/- 0.034
配列は特定の型にのみ使用できますが、リストは任意のオブジェクトに使用できます。
配列は 1 つの型のデータしか持てませんが、リストはさまざまなオブジェクト型のエントリを持つことができます。
配列は、一部の数値計算でもより効率的です。