注目キーワード
  1. Python
  2. コンペ

Pythonの内包表記の使い方:forループとの速度比較・if/else・二重ループを解説

  • 2026年6月29日
  • 2026年6月29日
  • Python
  • 4回
  • 0件

Pythonの内包表記とは

内包表記(comprehension)は、リストや辞書・集合などのコレクションを、簡潔に生成するための記法です。

通常のforループとappendを組み合わせた書き方を、1行にまとめることができます。コードの見通しがよくなるだけでなく、処理速度の面でも有利になるケースがあります。

この記事では、以下の内容を解説します。

  • リスト内包表記の基本的な書き方とforループとの比較
  • 条件付き(if)や if-else での絞り込みと変換
  • 二重ループのネスト
  • 辞書内包表記・集合内包表記
  • forループとの速度差の目安
  • 可読性の境界と使いどころ

基本の書き方:forループと内包表記の比較

まず、通常のforループで書いたコードを見てみます。

# forループ版
squares = []
for x in range(5):
    squares.append(x ** 2)
print(squares)
[0, 1, 4, 9, 16]

同じ処理を内包表記で書くと、次のようになります。

# 内包表記版
squares = [x ** 2 for x in range(5)]
print(squares)
[0, 1, 4, 9, 16]

構造は [式 for 変数 in イテラブル] です。forループ版と同じ結果を1行で書けます。

条件付きの内包表記(if)

末尾に if を付けると、条件に合う要素だけを絞り込めます。

# 偶数だけを取り出す
evens = [x for x in range(10) if x % 2 == 0]
print(evens)
[0, 2, 4, 6, 8]

for の後ろに if を置くのがポイントです。この if はフィルタとして機能し、条件を満たす要素だけがリストに入ります。

if-elseを使った変換(条件に応じて値を切り替える)

絞り込みではなく「条件によって値を変える」場合は、if-else を式の先頭側に置きます。

# 偶数なら"even"、奇数なら"odd"に変換
labels = ["even" if x % 2 == 0 else "odd" for x in range(6)]
print(labels)
['even', 'odd', 'even', 'odd', 'even', 'odd']

構造は [真の値 if 条件 else 偽の値 for 変数 in イテラブル] です。

末尾の if(フィルタ)と先頭の if-else(変換)は役割が異なります。混同しやすい部分なので整理しておきます。

書き方役割
[x for x in L if 条件]絞り込み(フィルタ)偶数だけ取り出す
[A if 条件 else B for x in L]変換(全要素を処理)偶数→A、奇数→B

複数条件を組み合わせる

if に複数の条件を andor でつなぐことができます。

# 3の倍数かつ5の倍数
fizzbuzz = [x for x in range(1, 31) if x % 3 == 0 and x % 5 == 0]
print(fizzbuzz)
[15, 30]

条件が複雑になる場合は、可読性のために関数に分けることも検討してください。

タプルを使った内包表記

内包表記の中でタプルを生成することもできます。

# (元の数, 2乗) のタプルのリスト
pairs = [(x, x ** 2) for x in range(5)]
print(pairs)
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16)]

式の部分にタプルを書く場合、括弧が必要です。括弧を外すと構文エラーになります。

# NG: 括弧なしはエラー
# pairs = [x, x ** 2 for x in range(5)]  # SyntaxError

二重ループの内包表記(ネスト)

forループを2つネストした処理も、内包表記で書けます。

# 九九の一部(2〜4の段)
table = [i * j for i in range(2, 5) for j in range(1, 4)]
print(table)
[2, 4, 6, 3, 6, 9, 4, 8, 12]

構造は [式 for 変数1 in イテラブル1 for 変数2 in イテラブル2] です。左から順にループが展開されます。

外側のループが先に来る点は、forループを2段階ネストしたときと同じ順序です。

# 上のコードと等価なforループ
table = []
for i in range(2, 5):
    for j in range(1, 4):
        table.append(i * j)

ネストが深くなると読みにくくなるため、3段階以上のネストは通常のforループで書く方が無難です。

辞書内包表記・集合内包表記

リスト以外にも、辞書(dict)や集合(set)を内包表記で生成できます。

辞書内包表記

# 文字列の長さを辞書にまとめる
words = ["apple", "banana", "cherry"]
length_dict = {w: len(w) for w in words}
print(length_dict)
{'apple': 5, 'banana': 6, 'cherry': 6}

{キー: 値 for 変数 in イテラブル} の形式です。

集合内包表記

# 重複を除いた集合を生成
nums = [1, 2, 2, 3, 3, 3, 4]
unique = {x for x in nums}
print(unique)
{1, 2, 3, 4}

波括弧を使い、{式 for 変数 in イテラブル} の形式です。辞書内包表記との違いは、コロン(:)がない点です。

forループとの速度比較

内包表記はforループ+appendよりも処理速度が速い傾向があります。

理由は、内包表記がPythonの内部で最適化されているためです。具体的には、ループのたびに append メソッドを呼び出すオーバーヘッドがなく、リストの生成処理が効率よく行われます。

簡単な比較例を示します。

import time

n = 1_000_000

# forループ版
start = time.time()
result = []
for x in range(n):
    result.append(x ** 2)
print(f"forループ: {time.time() - start:.4f}秒")

# 内包表記版
start = time.time()
result = [x ** 2 for x in range(n)]
print(f"内包表記: {time.time() - start:.4f}秒")

実行環境によって数値は変わりますが、内包表記の方が速くなるケースが多いです。おおむね以下のような傾向が確認できます。

forループ: 0.1234秒
内包表記: 0.0678秒

大量データのメモリに注意

要素数が多い場合、リストをすべてメモリに展開するのではなく、ジェネレータ式を使う方がメモリ効率がよいです。

# ジェネレータ式(角括弧ではなく丸括弧)
gen = (x ** 2 for x in range(1_000_000))
# 必要な時だけ1要素ずつ取り出す
print(next(gen))
print(next(gen))
0
1

全要素を一度に使わない場合は、ジェネレータ式の方がメモリ消費を抑えられます。

よくあるミスと注意点

変数名の衝突

内包表記の中で使う変数名は、外側のスコープには影響しません(Python 3.x 系)。

x = 100
result = [x for x in range(5)]  # 内包表記内のxは別スコープ
print(x)  # 外側のxは変わらない
100

Python 2では内包表記の変数がスコープ外に漏れる挙動がありましたが、現在の Python 3.x 系では問題ありません。

if-elseの位置を間違える

# NG: elseがない状態でifを先頭に置く → SyntaxError
# result = [x if x % 2 == 0 for x in range(5)]

# OK: elseとセットで先頭に置く
result = [x if x % 2 == 0 else -1 for x in range(5)]
print(result)
[0, -1, 2, -1, 4]

if を先頭(式の側)に置く場合は、必ず else とセットにする必要があります。

可読性を損なう書き方

内包表記はシンプルな処理を短く書くのに向いています。複雑な処理を1行に詰め込むと、かえって読みにくくなります。

# 読みにくい例(無理に1行に収めた場合)
# result = [f(x) for x in [g(y) for y in range(10)] if h(x)]

# 分けた方が読みやすい
inner = [g(y) for y in range(10)]
result = [f(x) for x in inner if h(x)]

ネストが深い、条件が複雑、処理が複数ステップにわたる場合は、通常のforループに戻す判断も重要です。

AI時代での補足

AIがPythonコードを生成する場面では、内包表記が使われることが増えています。出力を読んで「これは何をしているコードか」と判断できるかどうかは、内包表記の構造を理解しているかどうかにかかっています。forループとの対応を把握しておくと、AIの出力を自分の用途に合わせて修正しやすくなります。

まとめ

この記事では、Pythonの内包表記について以下の内容を解説しました。

  • [式 for 変数 in イテラブル] が基本形
  • 末尾の if はフィルタ、先頭の if-else は変換
  • 二重ループは for を並べて書く
  • 辞書内包表記は {キー: 値 for ...}、集合内包表記は {式 for ...}
  • forループより速い傾向があるが、複雑な処理には向かない
  • 大量データはジェネレータ式でメモリを節約できる

Pythonの if in 構文やメンバーシップテストについては、Python「if in」を徹底解説:効率的な条件分岐とメンバーシップテストの完全ガイド で詳しく解説しています。あわせて参照してください。

基礎をどこまで自分で習得すべきか迷っている場合は、AIが普及した時代にプログラミングスクールは必要か?【判断基準を解説】 も参考になります。

最新情報をチェックしよう!