3秒でわかる
繰り返しと条件をひとつの式にまとめて、新しいリストを作る Python の記法。空リストと append の 3 行を 1 行に置き換えられます。
もう少し詳しく
どういうものか
リスト内包表記は、for による繰り返しと絞り込みを角かっこの中に書いて、新しいリストを組み立てる Python の記法です。空のリストを用意して、繰り返しながら append する、という 3 行以上のかたまりを 1 つの式で表せます。読む順序は、最初に for、次に if、最後に左端の式です。
なぜ必要か
同じ処理を普通の for で書くと、リストを作る行、繰り返す行、条件の行、追加する行に分かれます。読む側は 4 行を追ってから、ようやく「元のリストを 2 倍した新しいリストを作っている」と理解します。内包表記なら、1 行を読んだ時点で結果の形が分かります。
もうひとつは、変数が外に漏れないことです。内包表記の中の変数は式の内側だけで有効なので、後続のコードに影響しません。速度の面でも、append をその都度呼び出す形より軽くなります。
具体例
# 普通の for で書いた場合
squares = []
for x in range(5):
squares.append(x ** 2)
# 内包表記
squares = [x ** 2 for x in range(5)] # [0, 1, 4, 9, 16]
# 条件で絞る
evens = [x for x in range(10) if x % 2 == 0]
# 値を分岐させる場合は if を式の側に置く
labels = ["偶数" if x % 2 == 0 else "奇数" for x in range(4)]
# 辞書やセットも同じ書き方でできる
prices = {"apple": 100, "banana": 80}
taxed = {k: int(v * 1.1) for k, v in prices.items()}
uniq = {len(w) for w in ["a", "bb", "cc"]}似た用語との違い
| 記法 | 作られるもの |
|---|---|
| 角かっこ | リスト |
| 波かっこでキーと値 | 辞書 |
| 波かっこで値のみ | セット |
| 丸かっこ | ジェネレータ。全件を一度に作らず、必要な分だけ生成する |
100 万件を処理して合計だけ求めるような場合は、リストを作らないジェネレータのほうがメモリを使いません。
つまずきやすいところ
絞り込みの if と、値を分岐させる if は書く位置が違います。for の後ろに置いた if は要素を除外し、式の前に置いた if else は値を選びます。除外したいのに if else を書くと、条件に合わない要素も別の値になって残ります。
もうひとつは詰め込みすぎです。for を 2 つ重ね、さらに条件を 2 つ入れた 1 行は、普通の for で書いたほうが読めます。1 行に収めること自体が目的になると、後から読む人の負担が増えます。
なお、内包表記の中で外側のリストを書き換えると結果が予測しにくくなります。内包表記は新しいリストを作るための記法であって、元のデータを更新する用途には向きません。