13

このコードでプル リクエストを送信しました。

my_sum = sum([x for x in range(10)])

レビュアーの 1 人は、代わりにこれを提案しました。

my_sum = sum(x for x in range(10))

(違いは、角括弧がないことだけです)。

2番目のフォームが同じように見えることに驚きました。しかし、最初のものが機能する他のコンテキストで使用しようとすると、失敗します:

y = x for x in range(10)
        ^ SyntaxError !!!

2 つのフォームは同一ですか? 関数で角括弧が必要ない重要な理由はありますか? それとも、これは私が知らなければならないことですか?

4

4 に答える 4

25

これはジェネレータ式です。スタンドアロンの場合に動作させるには、中括弧を使用します。

y = (x for x in range(10))

y はジェネレータになります。ジェネレーターを反復できるため、関数など、反復可能が期待される場所でsum機能します。

使用例と落とし穴:

>>> y = (x for x in range(10))
>>> y
<generator object <genexpr> at 0x0000000001E15A20>
>>> sum(y)
45

ジェネレーターを保持するときは注意してください。それらを通過できるのは 1 回だけです。したがって、上記の後にsum再度使用しようとすると、次のようになります。

>>> sum(y)
0

そのため、実際にリストやセット、または同様のものが期待されるジェネレーターを渡す場合は、注意が必要です。関数またはクラスが引数を格納し、それを複数回反復しようとすると、問題が発生します。たとえば、次のように考えてください。

def foo(numbers):
    s = sum(numbers)
    p = reduce(lambda x,y: x*y, numbers, 1)
    print "The sum is:", s, "and the product:", p

ジェネレーターを渡すと失敗します。

>>> foo(x for x in range(1, 10))
The sum is: 45 and the product: 1

ジェネレーターが生成する値から簡単にリストを取得できます。

>>> y = (x for x in range(10))
>>> list(y)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

これを使用して、前の例を修正できます。

>>> foo(list(x for x in range(1, 10)))
The sum is: 45 and the product: 362880

ただし、ジェネレーターからリストを作成する場合は、すべての値を保存する必要があることに注意してください。これは、アイテムがたくさんある状況では、より多くのメモリを使用する可能性があります。

あなたの状況でジェネレーターを使用する理由は何ですか?

sum(generator expression)がより優れている理由は、メモリ消費量がはるかに少ないことsum(list)です。ジェネレーター バージョンは単一の値のみを格納する必要がありますが、リスト バリアントは N 個の値を格納する必要があります。したがって、副作用の危険がないジェネレーターを常に使用する必要があります。

于 2012-06-12T14:17:05.577 に答える
6

それらは同一ではありません。

第一形態、

[x for x in l]

リスト内包表記です。もう 1 つはジェネレーター式であり、次のように記述されます。

(x for x in l)

リストではなく、ジェネレーターを返します。

ジェネレーター式が関数呼び出しの唯一の引数である場合、その括弧はスキップできます。

PEP 289を参照

于 2012-06-12T14:20:15.730 に答える
2

1つ目はリスト内包表記で、2つ目はジェネレーター式です

    (x for x in range(10))
    <generator object at 0x01C38580>
    >>> a = (x for x in range(10))
    >>> sum(a)
    45
    >>> 

ジェネレーターにブレースを使用します。

>>> y = (x for x in range(10))
>>> y
<generator object at 0x01C3D2D8>
>>> 
于 2012-06-12T14:19:14.450 に答える
0

このPEP を読んでください: 289

たとえば、次の合計コードは、メモリ内に正方形の完全なリストを作成し、それらの値を繰り返し処理し、参照が不要になったらリストを削除します。

sum([x*x for x in range(10)])

代わりにジェネレータ式を使用すると、メモリが節約されます。

sum(x*x for x in range(10))

データ ボリュームが大きくなるにつれて、ジェネレーター式のパフォーマンスが向上する傾向があります。これは、ジェネレーター式がキャッシュ メモリを使い果たしず、Python が反復間でオブジェクトを再利用できるようにするためです。

ブレース積ジェネレーターを使用します。

>>> y = (x for x in range(10))
>>> y
<generator object <genexpr> at 0x00AC3AA8>
于 2012-06-12T14:38:20.543 に答える