内包表記: Pythonic なループ
1行でリスト/辞書/セットを構築。Python らしい書き方。
内包表記とは?
なぜ内包表記が必要か?
内包表記(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で最も愛されている機能の一つです。
# リスト内包表記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: ループで構築result = []for x in range(10): if x % 2 == 0: result.append(x**2)# ✅ Good: 内包表記result = [x**2 for x in range(10) if x % 2 == 0]高度な使い方
# ネストしたループ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]合格ライン
演習課題
参考文献
この記事は以下の公的ガイドライン/標準に基づいています。
- Python Tutorial - List Comprehensions - 公式チュートリアル
- Python Dictionary Types - 辞書型ドキュメント
- Python itertools Module - itertools モジュール
- PEP 289 -- Generator Expressions - ジェネレータ式仕様