ジェネレータ式
このレッスンでできるようになること。ジェネレータ式で合計を求め、途中のリストを作らずに集計できるようになります。
これまでの内包表記は新しい入れ物を作りました。合計だけが欲しいときは、そのためのリストを作らず、数値を順に sum へ渡せます。走行距離の合計を例にします。
Python
distances = [3, 7, 2]
print(sum([km for km in distances])) # 12
print(sum(km for km in distances)) # 122行目の sum の引数は、角かっこを使わないジェネレータ式です。
ジェネレータ式は、値を全部作ってから渡すのではなく、必要になったときに1件ずつ作って渡すしくみです。リストを丸ごとメモリに置かずに済むので、支出が何万件になっても使うメモリはほとんど増えません。関数の引数がジェネレータ式ひとつだけのときは、上のように丸かっこを省いて書けます。
代わりに気をつける点があります。ジェネレータ式は1回しか読み取れません。変数に入れて sum を2回呼ぶと、2回目は0になります。また、len で件数を数えることもできません。中身を何度も使うなら、素直にリスト内包表記にしてください。
Python
gen = (km for km in distances)
first = sum(gen) # ここで中身を使い切る
second = sum(gen) # 0 になる合計以外にも、min や max、any や all といった「まとめて1つの答えを出す関数」とは相性がよく、同じ書き方がそのまま使えます。第4章の高階関数でも、この形は何度も出てきます。
for を2つ並べる場合も、左から外側、内側の順に読みます。末尾の if を通ったものだけ、左端の式で数値にして sum へ渡します。
Python
batches = [[-2, 3], [0, 4]]
squares = sum(n * n for batch in batches for n in batch if n > 0)
print(squares) # 25演習では月別データを1つの支出リストにする _all_expenses(monthly) を準備済みにします。ジェネレータ式には for を1つ書き、末尾の if で対象カテゴリを選んでから金額を sum へ渡してください。
要件
- リスト内包表記を作らず、sum にジェネレータ式を渡す
- expenses の中で category が一致する支出だけの金額を合計する
- 該当が無いときは 0 を返す