Pythonリスト内包表記を初心者向けに徹底解説!コードを短く、美しく書こう
こんにちは。ゆうせいです。
プログラミングを書いていると、何度も同じような処理を繰り返す場面がたくさん出てきますよね。特に、あるリストの要素を一つずつ取り出して、それぞれに何かの処理を加えて、新しいリストを作る、なんてことは日常茶飯事です。
もちろん、forループを使えば書くことはできます。でも、「もっと短く、もっとスマートに書けないかな?」と思ったことはありませんか?
実は、Pythonにはそんな願いを叶えてくれる、とっても便利な機能があるんです!
それが今回ご紹介する「リスト内包表記(List Comprehensions)」です。
リスト内包表記って、一体なに?
リスト内包表記を一言で説明すると、「既存のリストや他の順序を持ったデータ(これをイテラブルオブジェクトと呼びます)から、新しいリストを効率的に作成するための書き方」のことです。
「内包」なんて言葉が出てくると、少し難しく感じてしまうかもしれませんね。
これは、リストを作るための処理を、一行の式の中に「ぎゅっ!」と閉じ込めてしまうようなイメージから来ています。
例えるなら、ベルトコンベアを使った工場の生産ラインを想像してみてください。
- ベルトコンベアに流れてくる材料 → これが元のデータ(イテラブルオブジェクト)です。
- 材料を加工する機械 → これが各要素に行う処理(式)です。
- 完成した製品が箱に詰められていく → これが新しく作られるリストです。
リスト内包表記は、この一連の流れをたった一行で表現してしまう、魔法のような書き方なんですよ。
基本的な使い方を見てみよう!
言葉で説明するよりも、実際のコードを見てもらった方が分かりやすいですよね。
まずは、0から9までの数字をそれぞれ2乗したリストを作ってみましょう。
従来のforループで書くと…
squares = []
for i in range(10):
new_value = i * i
squares.append(new_value)
print(squares)
# 出力: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
このように、空のリストを用意して、forループで計算結果を一つずつ追加していくのが基本的な書き方です。
では、これをリスト内包表記で書いてみましょう!
リスト内包表記で書くと…
squares = [i * i for i in range(10)]
print(squares)
# 出力: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
どうでしょうか?たった一行で、さっきの4行のコードと同じ結果になりました!
とてもスッキリして、何をしているのかも一目で分かりやすいですよね。
基本的な構文はこうなっています。
[式 for 要素 in イテラブルオブジェクト]
for 要素 in イテラブルオブジェクト
の部分で、元のデータから要素を一つずつ取り出します。(ベルトコンベアに材料が乗るイメージ)式
の部分で、取り出した要素に対して行う処理を書きます。(機械が加工するイメージ)
条件(if)を追加して、さらに便利に!
リスト内包表記のすごいところは、これだけではありません。なんと、条件分岐のif文も組み込むことができるんです!
例えば、「0から9までの数字のうち、偶数だけを2乗したリスト」を作りたいとします。
先ほどの工場の例えで言うなら、ベルトコンベアに検査員を配置して、条件に合った材料だけを加工ラインに乗せるようなイメージです。
従来のforループで書くと…
even_squares = []
for i in range(10):
if i % 2 == 0: # 偶数かどうかをチェック
even_squares.append(i * i)
print(even_squares)
# 出力: [0, 4, 16, 36, 64]
リスト内包表記で書くと…
even_squares = [i * i for i in range(10) if i % 2 == 0]
print(even_squares)
# 出力: [0, 4, 16, 36, 64]
これもまた、一行で書けてしまいました!
構文は、for文の後ろにif文を追加するだけです。
[式 for 要素 in イテラブルオブジェクト if 条件式]
このように、if
を使うことで、リストに含める要素をフィルタリングすることができるんですね。
if-elseで処理を分ける応用テクニック
「じゃあ、ifだけじゃなくて、elseも使いたくなったらどうするの?」
良い質問ですね!もちろん、それも可能です。
例えば、「0から9までの数字が、偶数なら2乗し、奇数なら-1にする」という処理を考えてみましょう。
工場の例えで言うと、流れてくる材料の種類(条件)によって、機械が2パターンの加工を使い分けるイメージです。
この場合の構文は、少し順番が変わるので注意してください!
[真の場合の式 if 条件式 else 偽の場合の-式 for 要素 in イテラブルオブジェクト]
このように、for
の前に if-else
の塊を置きます。
実際のコードを見てみよう
result = [i * i if i % 2 == 0 else -1 for i in range(10)]
print(result)
# 出力: [0, -1, 4, -1, 16, -1, 36, -1, 64, -1]
少し複雑に見えるかもしれませんが、慣れてしまえばとても強力な武器になりますよ。
メリットとデメリットを整理しよう
リスト内包表記はとても便利ですが、どんなときでも使えば良いというわけではありません。メリットとデメリットをしっかり理解しておきましょう。
メリット | デメリット |
コードが短く、簡潔になる | 複雑な処理を書くと、かえって読みにくくなる |
実行速度がforループより速い場合がある | 初心者には理解が難しい場合がある |
やりたいことが一行で表現できる | デバッグがしにくいことがある(エラー箇所が分かりにくい) |
基本的には、シンプルな繰り返し処理で新しいリストを作りたい場合に使うのがおすすめです。もし処理が複雑になりすぎて一行で書くと分かりにくくなるようなら、無理せずforループで書く、という判断も大切ですよ!
他の言語にも似たような機能はあるの?
「この便利な書き方って、Pythonにしかないの?」と思うかもしれませんね。
実は、この「データのかたまりから、新しいデータのかたまりを作る」という考え方は、他の多くのプログラミング言語にも存在します。
もともと、リスト内包表記のアイデアは、Haskellという関数型プログラミング言語から来ています。
また、他の言語では少し違う形で実現されています。
- C#のLINQC#にはLINQ(Language Integrated Query:統合言語クエリ)という機能があります。これは、SQLというデータベースを操作する言語のように、様々なデータに対して問い合わせ(クエリ)を投げかけることができる機能で、リスト内包表記と非常によく似た処理が書けます。
- JavaScriptの高階関数Webページ作成などでよく使われるJavaScriptには、mapやfilterといった「高階関数」があります。高階関数とは、関数を引数として受け取ったり、関数を返り値として返したりできる関数のことです。
filter()
:条件に合う要素だけを抽出する(リスト内包表記のif
の役割)- map():各要素に処理を加えて新しい配列を作る(リスト内包表記の 式 の役割)これらを組み合わせることで、Pythonのリスト内包表記と同じような処理を実現できるんです。
言語によって名前や書き方は違えど、「元のデータ集合を、変換したり、絞り込んだりして、新しいデータ集合を作る」という発想は、現代のプログラミングにおいて非常に重要で、共通の考え方となっているんですね。
まとめ:さあ、リスト内包表記を使いこなそう!
今回は、Pythonの強力な機能「リスト内包表記」について解説しました。
- リスト内包表記は、forループを使ったリスト作成を一行でスマートに書くための記法
- if文を組み合わせることで、要素のフィルタリングも可能
- if-elseを使えば、条件に応じた処理の振り分けもできる
- コードは短くなるが、複雑にしすぎると読みにくくなるので注意!
最初は少し戸惑うかもしれませんが、簡単な処理からで良いので、ぜひ積極的に使ってみてください。「あ、このforループ、リスト内包表記で書けるかも?」と考える癖をつけるのが上達への近道です!
リスト内包表記に慣れたら、次は辞書のキーと値を効率的に作る「辞書内包表記」や、集合を作る「集合内包表記」、さらにはメモリを節約できる「ジェネレータ式」といった、兄弟のような機能にも挑戦してみるのがおすすめです。
あなたのPythonコードが、より美しく、より効率的になることを応援しています!