メインコンテンツにスキップ
モジュール 6 · レッスン 3 / 4コース内の 23/36~10 min
モジュールのレッスン (3/4)

ジェネレータ式

ジェネレータ式はリスト内包表記に似ていますが、 角括弧の代わりに 括弧 を使用します。その違いは劇的です: メモリ内にリストを構築するのではなく、オンデマンドで要素を生成します。 一度に一つずつ。

Python
gen = (n * n for n in range(1_000_000))
# istantaneo, memoria costante: nessun calcolo ancora fatto

list_comp = [n * n for n in range(1_000_000)]
# alloca 1M di int in memoria

Lazyness (遅延評価)

ジェネレーターは、誰かが次の値を要求するまで何も行いません。

Python
gen = (n * n for n in range(5))
next(gen)    # 0    (calcolato adesso)
next(gen)    # 1
next(gen)    # 4
# ... e così via, fino a StopIteration

それは枯渇します。すべての要素を消費した後は、永遠に空です。 再利用するには、再作成する必要があります。

いつ使用するか

結果を順番に消費する関数に渡すと、次のようになります。

Python
total = sum(n * n for n in range(1_000_000))
# nessuna lista intermedia, memoria costante

sum、any、all、max、min、"".join(...) はすべてジェネレーターを受け入れます。 外部関数に呼び出し括弧のみが必要な場合は、次のようにすることができます。 ジェネレーター自体は省略します:

Python
sum((n * n for n in range(10)))    # OK
sum(n * n for n in range(10))      # IDENTICO, più leggibile

any および all: 短絡

any(...) と all(...) は、答えが得られるとすぐに反復を停止します。 ジェネレーターを使用すると、次の要素は計算されません。

Python
nums = [1, 2, 3, 4, 5]
any(n > 3 for n in nums)    # True (si ferma a 4)
all(n > 0 for n in nums)    # True
all(n > 2 for n in nums)    # False (si ferma a 1)

パターン: 遅延パイプライン

Python
righe = (linea.strip() for linea in testo.splitlines())
non_vuote = (r for r in righe if r)
prime_dieci = []
for r in non_vuote:
    prime_dieci.append(r)
    if len(prime_dieci) == 10:
        break

巨大な入力であっても中間リストはありません。

sum、any、all を使用してジェネレーターを使用する

ジェネレーター式は、sum()、any()、all() などの反復可能オブジェクトを使用する関数に直接渡すのに最適です。この場合、ジェネレータ式の外側の括弧を省略して、単に次のように記述することができます。

Python
squares_sum = sum(x**2 for x in range(10))

これにより、コードがクリーンになり、メモリ効率が高くなります。

試してみてください

運動#python.m6.l3.e1
試行回数: 0読み込み中…

sum() 内のジェネレーター式を使用して、1 から 100 (両端を含む) までの数値の二乗和を計算します。それを「tot」に代入します。 「tot」を評価します。

エディターを読み込み中…
ヒントを表示

range(1, 101) には 100 が含まれます。

3 回の試行後に解決策が利用可能になります

復習演習

運動#python.m6.l3.e2
試行回数: 0読み込み中…

`words = ['ciao', 'mondo', 'PYTHON', 'java']` とすると、ジェネレーター式で any() を使用して、少なくとも 1 つの単語が大文字かどうかを確認します (.isupper())。結果を `has_uppercase` に代入します。 `has_uppercase` を評価します。

エディターを読み込み中…
ヒントを表示

any(p.isupper() for p の単語)

3 回の試行後に解決策が利用可能になります

追加の課題

運動#python.m6.l3.e3
試行回数: 0読み込み中…

Use a generator expression passed directly to the `sum()` function to calculate the sum of the squares of all integers from 1 to 100 inclusive. Store the result in `total_sum` and evaluate it.

エディターを読み込み中…
ヒントを表示

total_sum = sum(x**2 for x in range(1, 101)) と書きます。二重括弧は必要ありません。

3 回の試行後に解決策が利用可能になります