「Pythonのコードを読んでいたら [x * 2 for x in nums] みたいな1行が出てきて、何をしているのか分からない…」
「for文で書けるのに、わざわざ1行にする意味ってあるの?」

Pythonを学び始めてしばらくすると、こんな疑問にぶつかりますよね。

この書き方は リスト内包表記(list comprehension) と呼ばれる、Pythonらしさが詰まった文法です。最初は暗号のように見えますが、「for文の書き換え」だと分かれば、すぐに読めるようになります。

この記事は、for文・if文・リストの基本が分かるPython初心者〜初級者向けです。for文と並べて比べながら、一緒に見ていきましょう!😊

リスト内包表記ってどんなもの?

conveyor belt sorting
conveyor belt sorting / Photo by Jonathan David via Pexels

ざっくり言うと、「空のリストを用意して、for文で1つずつ append する」処理を1行で書く方法です。

形はこうなっています。

  • [式 for 変数 in リスト] … 全部の要素を「式」で変換して新しいリストを作る
  • [式 for 変数 in リスト if 条件] … 条件に合う要素だけを残す

イメージとしては、「リストの各要素を、ベルトコンベアに乗せて加工し、新しい箱に詰め直す」感じです。元のリストは変わらず、新しいリストができあがります。

for文と内包表記を並べて比べてみよう

テストの点数リストを使って、「全員に5点加算」「合格点だけ取り出す」「合格・再試験の判定」の3つをやってみます。

# テストの点数リスト
scores = [72, 45, 88, 91, 60, 38, 79]

# --- for文で書いた場合 ---
bonus_for = []
for s in scores:
    bonus_for.append(s + 5)

# --- リスト内包表記で書いた場合(1行!) ---
bonus = [s + 5 for s in scores]
print("5点加算:", bonus)
print("for文と同じ結果?", bonus == bonus_for)

# 条件で絞り込む(60点以上だけ残す)
passed = [s for s in scores if s >= 60]
print("合格点だけ:", passed)

# 値を変換する(60点以上は「合格」、それ以外は「再試験」)
results = ["合格" if s >= 60 else "再試験" for s in scores]
print("判定:", results)
for文とリスト内包表記で点数リストを加工した実行結果
for文とリスト内包表記で点数リストを加工した実行結果

実行すると、上の画像のように表示されます。for文で4行かかっていた処理が、内包表記では1行になり、結果もまったく同じ(True)ですね。

ポイントをまとめるとこんな感じです👇

  • [s + 5 for s in scores]:先頭の s + 5 が「新しいリストに入れる値」、後ろの for s in scores がいつものfor文
  • [s for s in scores if s >= 60]:後ろに付けた if は「絞り込み」。条件に合わない要素はリストに入らない(7個 → 5個に減っています)
  • ["合格" if s >= 60 else "再試験" for s in scores]:前に書いた if〜else は「値の切り替え」。要素の数は変わらない(7個のまま)

⚠️ if の位置で意味が変わる(よくあるエラー)

ここが一番つまずきやすいポイントです。

「60点未満は0にしたい」と思って [s for s in scores if s >= 60 else 0] と書くと、実際に試したところ SyntaxError: invalid syntax になりました。

後ろの if は「絞り込み」専用なので、else は付けられないんです。値を切り替えたいときは、if〜else を for の前に移動して [s if s >= 60 else 0 for s in scores] と書きます。

  • 要素を減らしたい → if は 後ろ(else なし)
  • 要素の値を変えたい → if〜else は 前

この2つを覚えておくだけで、内包表記のエラーの多くは防げますよ。

辞書・集合・2重ループにも使える

内包表記はリストだけのものではありません。{} で囲むと 辞書内包表記 や 集合内包表記 になります。2重ループも書けます。

names = ["佐藤", "鈴木", "高橋", "田中"]
scores = [72, 45, 88, 91]

# 辞書内包表記:名前→点数の辞書を作る
score_dict = {name: score for name, score in zip(names, scores)}
print("辞書:", score_dict)

# 辞書から条件に合う人だけ取り出す
top = {name: s for name, s in score_dict.items() if s >= 80}
print("80点以上:", top)

# 集合内包表記:重複を除いた「十の位」
tens = {s // 10 * 10 for s in [72, 45, 88, 91, 60, 38, 79, 75]}
print("点数帯:", sorted(tens))

# 2重ループ:九九の表の一部を2次元リストで作る
table = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print("2次元リスト:", table)

# 2次元リストを平らにする(forを2つ並べる)
flat = [x for row in table for x in row]
print("平らにすると:", flat)
辞書・集合内包表記と2重ループの実行結果
辞書・集合内包表記と2重ループの実行結果

実行すると、上の画像のようになります。

ここが重要です👇

  • {キー: 値 for ...} のようにコロンがあると辞書、{式 for ...} のようにコロンがないと集合になる
  • zip() と組み合わせると、2つのリストから一気に辞書が作れる
  • 辞書から絞り込むときは .items() でキーと値を一緒に取り出す
  • 集合は重複が自動で消えます。8個の点数から「点数帯」が6種類だけ残りました(集合は順番を持たないので、表示前に sorted() で並べています)
  • [x for row in table for x in row] の2重ループは、for を「普通のfor文を書くときと同じ順番」で左から並べるのがコツ

これ、実行せずに答えられますか? [[i * j for j in range(1, 4)] for i in range(1, 4)] は、内側の [...] が1行分のリストを作り、それを外側のforで3回くり返しています。だから結果は3×3の2次元リストになるわけです。

内包表記は速い?実際に測ってみた

「内包表記のほうが速い」とよく言われるので、標準ライブラリの timeit で実際に測ってみました。

import timeit

def use_for():
    result = []
    for i in range(10000):
        result.append(i * 2)
    return result

def use_comp():
    return [i * 2 for i in range(10000)]

# それぞれ1000回実行して時間を測る
t_for = timeit.timeit(use_for, number=1000)
t_comp = timeit.timeit(use_comp, number=1000)
print(f"for文 + append : {t_for:.3f} 秒")
print(f"リスト内包表記 : {t_comp:.3f} 秒")
print(f"内包表記は約 {t_for / t_comp:.1f} 倍速い")

筆者の環境(Windows・Python 3.13)で実行したところ、for文+append が 0.248秒、リスト内包表記が 0.192秒 で、内包表記のほうが約1.3倍速いという結果になりました。何度か実行すると数値は少しぶれますが、内包表記がわずかに速い傾向は同じでした。

速くなるのは、for文版が毎回 result.append というメソッドを探して呼び出しているのに対し、内包表記はリストに要素を追加する処理がPython内部で最適化されているためです。

ただし、差は「劇的」というほどではありません。内包表記を使う一番の理由は、速さよりも「短くて読みやすいこと」だと考えておくのがよいと思います。

使いすぎに注意!for文に戻したほうがいい場面

便利な内包表記ですが、何でも1行に詰め込むと逆に読みにくくなります。次のようなときは、素直にfor文で書くのがおすすめです。

  • forが3つ以上ネストするとき(2つまでが目安)
  • if〜else が入り組んで、1行が画面からはみ出すとき
  • print() やファイル保存など、リストを作ることが目的ではない処理をくり返すとき([print(x) for x in nums] は不要なリストを作るだけなので、for文で書きましょう)

「内包表記は新しいリスト(辞書・集合)を作るための道具」と覚えておくと、使いどころを迷わなくなりますよ。

まとめ

  • リスト内包表記は、「空リスト+for+append」を1行で書くPythonの文法
  • 後ろの if は絞り込み、前の if〜else は値の切り替え。逆に書くと SyntaxError
  • {k: v for ...} で辞書、{x for ...} で集合も作れる。2重ループは for を左から順に並べる
  • for文より少し速いが、一番のメリットは短く読みやすいこと。複雑になったらfor文に戻す

「むずかしそう」に見えていた1行も、for文に分解して読めば怖くありません。まずは自分が書いたfor文を1つ、内包表記に書き換えるところから、ぜひ試してみてください🚀

\ 読んだら、次は自分で作ってみよう /

筆者が運営する無料の入門コース「作って学ぶPythonプログラミング入門」では、こうした基本文法を、割り勘計算機・おみくじ・数当てゲームなどを作りながら身につけます。各章末の定着ドリル(全42問)で、自分の手で書く練習まで。最初の4レッスンは登録なしで読めます。

→ 無料の入門コース(全7章52レッスン)を見てみる

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る
Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

もしも

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

FastAPIでWebAPI開発を実践的に学ぶ

Amazonで見る
ESP32&Arduino 電子工作 プログラミング入門

もしも

ESP32&Arduino 電子工作 プログラミング入門

ESP32とArduinoで電子工作を学ぶ入門書

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。