内包表記: Pythonic なループ

1行でリスト/辞書/セットを構築。Python らしい書き方。

リスト内包表記
[expr for x in iter] 形式。
辞書内包表記
{k: v for ...} 形式。
ジェネレータ式
(expr for x in iter) 遅延評価。

内包表記とは?

スムージーミキサー (Smoothie Blender)

内包表記(Comprehension)は「全自動スムージーミキサー」です。「生のフルーツ(元のリスト)」を入れると、一瞬で「カットして皮を剥いて(加工して)」、「腐ったものは捨てて(フィルタリングして)」、美味しい「スムージー(新しいリスト)」を作ってくれます。

なぜ内包表記が必要か?

内包表記(Comprehension)は「1行でリスト・辞書・セットを構築する」ための仕組みです。ループを使ってリストを作成する場合、通常「空のリストを用意 → ループで回す → 条件チェック → append」という4行の作業が必要です。内包表記を使うと、これを1行の美しい数式のように書けます。また、内包表記はリスト操作を宣言的(宣言型プログラミング)に書けるため、コードが読みやすく、バグが発生しにくくなります。Pythonで最も愛されている機能の一つです。

いつ使うか?

内包表記は、以下のような場面で使います: 1. **リストのフィルタリング**: 特定の条件を満たす要素だけを抽出したいとき。 2. **リストの変換**: 各要素に処理を適用して新しいリストを作りたいとき。 3. **辞書・セットの構築**: キーと値のペアや一意な値の集合を作りたいとき。 4. **ネストしたデータ構造のフラット化**: 2次元配列を1次元配列に変換したいとき。 5. **ジェネレータ式**: メモリ効率を考慮して、遅延評価したいとき。

実践テクニック

可読性を優先する

内包表記は便利ですが、複雑になりすぎると可読性が低下します。ネストが深い内包表記(3層以上)や、複雑な条件式を含む内包表記は、普通のループに戻すことを推奨します。可読性を優先し、他の開発者が理解しやすいコードを書いてください。

ジェネレータ式を活用する

リスト内包表記の代わりにジェネレータ式(`(x for x in iter)`)を使うと、遅延評価が可能です。ジェネレータ式は要素を1つずつ生成するため、大きなリストを扱う場合にメモリ効率が向上します。また、`itertools` モジュールの `chain()`、`zip_longest()` などの関数と組み合わせると、より強力なデータ処理が可能です。

辞書内包表記を使う

辞書内包表記(`{k: v for k, v in iter}`)を使うと、キーと値のペアを簡潔に作成できます。例:`{word: len(word) for word in words}` のように、1行で単語とその長さの辞書を作成できます。また、`zip()` 関数と組み合わせると、2つのリストから辞書を作成することも可能です。例:`{key: value for key, value in zip(keys, values)}`。

条件式と三項演算子

内包表記内で条件式を使う場合、三項演算子(`x if condition else y`)を活用できます。例:`[x if x % 2 == 0 else x * 2 for x in range(10)]` のように、条件に応じて異なる値を返せます。ただし、複雑な条件式は可読性を低下させるため、シンプルな条件にとどめることを推奨します。

セット内包表記を使う

セット内包表記(`{x for x in iter}`)を使うと、一意な値の集合を作成できます。例:`{x % 2 == 0 for x in range(20)}` のように、偶数だけのセットを作成できます。セットは重複を自動的に排除するため、一意な値のリストを作りたい場合に便利です。また、セットは高速なメンバーシップテスト(`in` 演算子)をサポートするため、存在チェックが高速です。

itertoolsモジュールと組み合わせる

Pythonの `itertools` モジュールには、内包表記と組み合わせると強力な関数が多数用意されています。`chain()` は複数のイテラブルを連結し、`zip_longest()` は長さの異なるリストを最長の長さまで埋めて結合します。また、`groupby()` はキーに基づいて要素をグループ化できます。これらの関数を内包表記と組み合わせると、より簡潔で強力なデータ処理が可能です。

「空のリストを用意 → ループで回す → 条件チェック → append」という4行の作業を、たった1行の美しい数式のように書けます。Pythonで最も愛されている機能の一つです。

Comprehension Types
# リスト内包表記
squares = [x**2 for x in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 条件付き
evens = [x for x in range(10) if x % 2 == 0]
# [0, 2, 4, 6, 8]
# 辞書内包表記
word_lengths = {word: len(word) for word in words}
# セット内包表記
unique_lengths = {len(word) for word in words}
# ジェネレータ式(遅延評価)
gen = (x**2 for x in range(10))
Bad
# ❌ Bad: ループで構築
result = []
for x in range(10):
if x % 2 == 0:
result.append(x**2)
Good
# ✅ Good: 内包表記
result = [x**2 for x in range(10) if x % 2 == 0]

高度な使い方

Nested & Walrus
# ネストしたループ
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [x for row in matrix for x in row]
# [1, 2, 3, 4, 5, 6]
# 条件式(三項演算子)
labels = ['even' if x % 2 == 0 else 'odd' for x in range(5)]
# ['even', 'odd', 'even', 'odd', 'even']
# ネストした辞書
nested = {
outer: {inner: inner**2 for inner in range(3)}
for outer in ['a', 'b']
}
# ウォルラス演算子 (Python 3.8+)
results = [y for x in data if (y := process(x)) is not None]
Tip: 複雑になりすぎたら普通のループに戻す。可読性優先。

合格ライン

リスト・辞書・セット内包表記を使える
ジェネレータ式との違いを説明できる

演習課題

課題1: リスト内包表記
リスト内包表記で偶数だけをフィルタしてください。
課題2: 辞書内包表記
辞書内包表記でキーと値を変換してください。

参考文献

この記事は以下の公的ガイドライン/標準に基づいています。