13

次のスニペットは、2つの入力反復可能変数のデカルト積からペアを生成する反復子を提供することを期待します。

$ python
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import itertools
>>> one = xrange(0, 10**9)
>>> two = (1,)
>>> prods = itertools.product(one, two)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError

代わりに、を取得しMemoryErrorます。itertools.productしかし、それは中間結果をメモリに保存しなかったと思ったので、何が原因MemoryErrorですか?

4

3 に答える 3

17

中間結果は保存されませんが、複数の出力値に対してそれぞれが数回必要になる可能性があるため、入力値を保存する必要があります。

イテレータで反復できるのは1回だけなので、productこれと同等に実装することはできません。

def prod(a, b):
  for x in a:
    for y in b:
       yield (x, y)

ここbにイテレータがある場合、外側のループの最初の反復の後にそれは使い果たされ、その後のの実行でそれ以上の要素は生成されませんfor y in b

productによって生成されるすべての要素を格納することでこの問題を回避しb、繰り返し使用できるようにします。

def prod(a, b):
  b_ = tuple(b)  # create tuple with all the elements produced by b
  for x in a:
    for y in b_:
       yield (x, y)

実際、product最初のパラメーターでは回避できたとしても、指定されたすべての反復可能オブジェクトによって生成された要素を格納しようとします。関数は最初の反復可能オブジェクトを1回だけウォークオーバーする必要があるため、これらの値をキャッシュする必要はありません。しかし、それはとにかくやろうとします、それはMemoryErrorあなたが見ることにつながります。

于 2012-01-01T21:32:47.457 に答える
7

itertools.product中間製品はメモリに保存されませんtupleが、元のイテレータのバージョンは保存されます。

itertoolsこれは、モジュールのソースを見るとわかります。Modules/itertoolsmodule.cPython2.7.2ソースディストリビューションのファイルにあります。そこで、 1828行目以降の関数product_new(基本的にはオブジェクトのコンストラクター)に次のことがわかります。product

for (i=0; i < nargs ; ++i) {
    PyObject *item = PyTuple_GET_ITEM(args, i);
    PyObject *pool = PySequence_Tuple(item);
    if (pool == NULL)
        goto error;
    PyTuple_SET_ITEM(pools, i, pool);
    indices[i] = 0;
}

そのコードでargsは、への引数productです。このコードピースの3行目では、ith引数がタプルに変換されています。したがって、コードはイテレータxrange(0, 10**9)をタプルに変換しようとし、結果としてMemoryError

なぜitertools.productこのように振る舞うのかわかりません。各入力イテレータをタプルとして格納する代わりに、各イテレータから返された最後のアイテムを格納するだけで十分なはずです。(編集:理由についてはsthの回答を参照してください)

于 2012-01-01T21:16:32.023 に答える
0

問題は、xrangeが独自の特殊な種類のオブジェクトを返すことである可能性があると思います。これは通常の反復可能ではありません。

xrangeは、(リストと同様に)オブジェクトを何度も反復できるように実装されていますが、通常のジェネレーターオブジェクトは1回だけ反復できます。したがって、おそらくこの機能の何かがメモリエラーの原因です。

于 2012-01-01T21:20:20.017 に答える