Menu
日本語

Python内包表記の書き方|リスト・辞書・フィルタ完全ガイド

for文とappendを1行で書き換えられるのがリスト内包表記。値の変換もフィルタリングも、スッキリ読みやすく書けるPythonらしい書き方です。

1行に1つのアイデアを

もう何度も書いてきたパターンですよね。空のリストを用意して、何かをループで回し、条件で絞り込んで、結果にappendしていく。

main.py
Output
Click Run to see the output here.

リスト内包表記を使えば、これを1行で書けます。

main.py
Output
Click Run to see the output here.

左から順に読んでみましょう。「numbers の各要素 n について、n * 2 を並べた新しいリスト」となります。基本の形は [式 for 要素 in イテラブル] です。

これは Python 特有のテクニックというわけではなく、一般に 内包表記(comprehension) と呼ばれるものです。リストの作り方を手続き的に書き下すのではなく、「何が入るか」を宣言的に記述する書き方、というのがポイントです。

if で絞り込む

ループ部分の後ろに if を付けると、条件でフィルタできます。

main.py
Output
Click Run to see the output here.

2つ目は「numbers の各 n について n * n、ただし n が奇数のときだけ」と読みましょう。

同じ処理をループで書くと次のようになります。

main.py
Output
Click Run to see the output here.

どちらでも問題ありません。内包表記の方が短くて済みますし、慣れてくると「何をしているか」が1行にまとまっているので、かえって読みやすく感じるはずです。

map と filter を内包表記でまとめる

値を関数に通しつつ、同時に条件で絞り込むこともできます。

main.py
Output
Click Run to see the output here.

3文字より長い単語だけ、大文字版も一緒に含めます。

内包表記でのネストしたループ

for を2つ並べると、直積(デカルト積)のような組み合わせが作れます。

main.py
Output
Click Run to see the output here.

順序はループをネストした場合と同じで、最初の for が外側、2 つ目が内側になります。インデントした通常のループと同じく、前から順に読んでいける形です。

ネストは 2 段までが実用的な限界で、それ以上深くなるなら普通のループで書いたほうが読みやすくなります。3 段になったら迷わずループに戻しましょう。

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

考え方はリスト内包表記と同じで、括弧の種類が変わるだけです。

main.py
Output
Click Run to see the output here.

集合内包表記はパッと見、辞書内包表記とほぼ同じに見えます。違いは key: value の形か、式がひとつだけかという点。中括弧に : があれば辞書、: がなければ集合、と覚えておけばOKです。

ジェネレータ式

リスト内包表記とほぼ瓜二つですが、角括弧ではなく丸括弧を使います。そして何より大事なのは、リストを作らないという点です。

main.py
Output
Click Run to see the output here.

ジェネレータを sum()any() にそのまま渡している点に注目してください。余計な括弧は不要です。ジェネレータ式は、呼び出し側が一度だけイテレートできればいい場面にぴったりの道具です。大きなコレクションを扱うときは、リストを丸ごと作るよりメモリに優しくなります。

内包表記ではなく普通のループを使うべきとき

内包表記は魅力的で、その気になれば1行にいくらでも詰め込めます。でも、詰め込むべきではありません。

次のような場合は、素直に for ループで書きましょう。

  • 変換処理が2段階以上にわたるとき。途中の変数が必要なら、ループとして展開したほうが読みやすくなります。
  • 複雑なエラーハンドリングや分岐が絡むとき。
  • その1行を読む人が、理解するのに何度も止まって考え込むようなとき。

私がいつも使っている基準は、「一息で読めて意味がすぐ分かる内包表記ならOK、つっかえたらループに書き直す」というものです。

一見賢そうでも、かえって可読性を損なう内包表記もあります。

main.py
Output
Click Run to see the output here.

結果は同じです。ループ版は1行ではなく5行になりますが、「長い=悪い」というわけではありません。

よく使うパターンをいくつか

main.py
Output
Click Run to see the output here.

この 5 つのパターンを押さえておくだけで、日常的なデータ処理のかなりの部分はカバーできてしまいます。

次のステップ

ここまでで、主要なコレクション型と、それらを結びつける内包表記について一通り見てきました。次の章では関数を取り上げます。処理をひとつの名前にまとめて、何度でも再利用できる形にパッケージングしていきましょう。

よくある質問

リスト内包表記とは何ですか?

既存のイテラブルから新しいリストを作るための、コンパクトな書き方です。たとえば [x * 2 for x in numbers] と書けば、各要素を2倍にした新しいリストができます。[x for x in numbers if x > 0] のように if を付ければフィルタもまとめて書けます。

リスト内包表記を使わない方がいいのはどんなとき?

読みにくくなるときです。内側の式が複雑だったり、ネストが深くなってきたら、普通の for ループに変数名を付けて書いた方がずっと分かりやすくなります。内包表記はあくまで シンプルな 変換・抽出のためのもの、と割り切るのがコツです。

リスト内包表記とジェネレータ式の違いは?

リスト内包表記はリスト全体をメモリに作ります。一方、ジェネレータ式(書き方はほぼ同じで、括弧が () になる)は要素を1つずつ生成します。sum(...) のように一度舐めるだけで捨てるような処理に渡すなら、ジェネレータ式の方が無駄がありません。

Coddyでコードを学ぼう

始める