L03 ch03 — 内包表記 (comprehension)
テクノロジ系 / L04 loop — ループ
L03 ch03 — 内包表記 (comprehension)
「for + append」を 1 行に圧縮する Python の定番テクニック
ゴール
- リスト内包表記の構文を書ける
ifフィルタ付き内包表記を書ける- 辞書内包表記 / 集合内包表記を書ける
- 「使うべき場面」と「使うと読みづらい場面」の境界を判断できる
なぜ内包表記なのか
for + append の冗長さを排除し、「何を作るか」を 1 行で示す。
# ❌ 冗長
squares = []
for x in range(5):
squares.append(x * x)
# ✅ 内包表記
squares = [x * x for x in range(5)]
# → [0, 1, 4, 9, 16]基本構文
[ <式> for <変数> in <イテラブル> ]
nums = [1, 2, 3, 4] doubled = [n * 2 for n in nums] # → [2, 4, 6, 8] names = ["taro", "jiro"] upper = [n.upper() for n in names] # → ["TARO", "JIRO"]
if フィルタ
[ <式> for <変数> in <イテラブル> if <条件> ]
nums = [1, 2, 3, 4, 5, 6] evens = [n for n in nums if n % 2 == 0] # → [2, 4, 6] squares_of_odd = [n * n for n in nums if n % 2 == 1] # → [1, 9, 25]
if-else は「式」の位置に書く
if の位置で意味が変わる。
nums = [1, 2, 3, 4] # フィルタ (条件を満たすものだけ残す) [n for n in nums if n % 2 == 0] # → [2, 4] # 三項演算 (全部残すが値を分岐) ["even" if n % 2 == 0 else "odd" for n in nums] # → ["odd", "even", "odd", "even"]
辞書内包表記
names = ["taro", "jiro", "saburo"]
# index → name の辞書
name_map = {i: n for i, n in enumerate(names)}
# → {0: "taro", 1: "jiro", 2: "saburo"}
# 文字列長の辞書
lengths = {n: len(n) for n in names}
# → {"taro": 4, "jiro": 4, "saburo": 6}集合内包表記
words = ["apple", "banana", "apple", "cherry", "banana"]
unique_lengths = {len(w) for w in words}
# → {5, 6} (重複は自動排除){} でも辞書か集合かは中身で判別される (k: v なら dict、単独値なら set)。
ネスト (二重ループ)
pairs = [(x, y) for x in [1, 2] for y in [10, 20]] # → [(1, 10), (1, 20), (2, 10), (2, 20)] # 行列の flatten matrix = [[1, 2, 3], [4, 5, 6]] flat = [v for row in matrix for v in row] # → [1, 2, 3, 4, 5, 6]
外側 for を先に書く (通常の for ネストと同じ順)。
ジェネレータ式
[] を () にすると遅延評価のジェネレータになる。
# リスト (全要素をメモリに展開) total = sum([n * n for n in range(1_000_000)]) # ジェネレータ (1 要素ずつ評価 = 省メモリ) total = sum(n * n for n in range(1_000_000))
sum / any / all / max に渡すときは () 推奨。
drill
drill/01-fill-listcomp/ — 偶数のみを 2 倍にして返すリスト内包表記を完成させる
使うべきでない場面
内包表記は「1 行で意図が読める」前提の道具。複雑になったら for に戻す。
# ❌ 読みづらい (条件 + 三項 + ネスト)
result = [
f(x) if x > 0 else g(x)
for row in data
for x in row
if x is not None and x != 0
]
# ✅ for ループに分解
result = []
for row in data:
for x in row:
if x is None or x == 0:
continue
result.append(f(x) if x > 0 else g(x))よくある詰まり
| 症状 | 原因 | 対処 |
|---|---|---|
SyntaxError で if が通らない | if-else を for の後に書いた | 三項なら式の位置 [a if c else b for ...] |
| 辞書のつもりが set になる | {x for x in xs} と書いた | {k: v for ...} の形にする |
| 巨大データで MemoryError | リストで全展開した | () のジェネレータ式に変える |
次に学ぶ領域
| 領域 | 続けて読む |
|---|---|
ジェネレータ関数 (yield) | function/ 後続 chapter |
map / filter との比較 | 関数型スタイル chapter |
itertools | 標準ライブラリ chapter |
力試ししたい方は クイズ形式の演習(任意) もあります。読むだけでも十分です。