2.30. 内包表記¶
内包表記は、既存のイテラブルから新しいリスト、セット、辞書、またはジェネレータを1つの式で構築します。空のコンテナから始めてループ内で追加していくという一般的なパターンの代替です。
2.30.1. リスト内包表記¶
squares = [x * x for x in range(5)]
print(squares)
出力:
[0, 1, 4, 9, 16]
同じループを展開して書くと:
squares = []
for x in range(5):
squares.append(x * x)
内包表記の形式は、その場でリストを構築する1つの式です。squares = [] も .append もありません。結果は内包表記の値そのものです。
先頭の式が各項目を生成し、for 句がループ変数に名前を付け、省略可能な if が項目をフィルタで除外します。¶
2.30.2. ifによるフィルタリング¶
省略可能な if 句は、一致する項目だけを残します:
evens = [x for x in range(10) if x % 2 == 0]
print(evens)
出力:
[0, 2, 4, 6, 8]
フィルタは先頭の式より先に実行されます。x % 2 == 0 が最初にチェックされ、一致する値だけが出力のために x に到達します。
2.30.3. 辞書内包表記とセット内包表記¶
同じ形が辞書リテラルやセットリテラルでも機能します。
辞書内包表記は、for の前に key: value のペアを持ちます:
squares = {x: x * x for x in range(5)}
print(squares)
出力:
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
セット内包表記は波括弧と単一の式を使います:
unique_lengths = {len(w) for w in ["a", "bb", "c", "bb"]}
print(unique_lengths)
出力:
{1, 2}
2.30.4. ジェネレータ式¶
丸括弧はリストの代わりにジェネレータ式を生成します。値は必要に応じて1つずつ計算されます:
total = sum(x * x for x in range(1000))
100万要素のリストが構築されることは決してありません。値は1つずつ sum() に流れ込み、加算されながら各値が順に破棄されていきます。
ジェネレータ式は、値を縮約関数(sum()、max()、any()、all())やその他のイテレータを消費するコードに渡すときの正しい選択です。同等のリストが使うはずだったメモリを節約できます。
2.30.5. 内包表記を使うべきでないとき¶
内包表記は簡潔ですが、必ずしもより分かりやすいとは限りません。次のような場合は素直な for ループを使いましょう:
本体に複数の文が必要な場合(内包表記にちょうど1つの式しか収まりません)。
本体に副作用がある場合(出力やファイルへの書き込みなど)。内包表記はコレクションを構築するためのものであり、アクションを実行するためのものではありません。
フィルタや変換の構成要素が多すぎて、内包表記がもはや左から右へ読めなくなる場合。