\ BLACK FRYDAY! /

【Python】リスト内包表記と辞書内包表記を基礎を解説!

  • 内包表記って書き方がよくわからない…
  • コードを見ても意味がわからない!

このような疑問にお答えします。

Python では内包表記がごく簡単に書けるため、Python を象徴するものとして挙げられることが多いです。(他の言語では存在はしている)

この内包表記ですが、簡潔に書ける一方で初学者は以下のように混乱しがちです。

  • 内包表記を組み立てられない
  • 内包表記を読んで意味を理解できない

これらは、内包表記の書き方をしっかりと理解すれば解決できます。

本記事では内包表記について丁寧に解説していきますので、不安がある方はぜひじっくりと読み進めてみてください!

内包表記の概略を理解しよう!

内包表記は、新たにリストや辞書などを生成するための方法です。

forループとifステートメントを含むコードを一行(ワンライナー)で書けるのが魅力。

ただし、あまりにも複雑なロジックはfor文で書くことを推奨します。極端に読みづらくなってしまうためです。

例えば、次のようなfor文を使ったコードがあったとします。

evens_squared = []
for x in range(10):
    if x % 2 == 0:
        evens_squared.append(x**2)

このコードでは0から9までの数字のうち偶数だけを抽出し、要素を二乗してリストに格納していくものになります。

これをリスト内包表記で書き換えると、以下になります。

evens_squared = [x**2 for x in range(10) if x % 2 == 0]

この段階では意味不明だと思いますが、とにかく「一行で簡潔に書けるのだ!」ということをご理解いただければと思います。

リスト内包表記の書き方

ここからは特定の要素を持つ新たなリストを作成する、リスト内包表記の使い方をご説明します。

  • リスト内包表記の基本的な書き方
  • 複数の条件を持つリスト内包表記の書き方

順番にレベルアップしていきますので、順に解説していきます。

リスト内包表記の基本的な書き方

リスト内包表記の文法は以下のようになります。

new_list = [expression for item in iterable if condition]

if以降は必須ではありません。

まずは単純な例として、0から9までの数値の2乗した数値を順次リストに加えたい場合を考えます。

squares = [x**2 for x in range(10)]

コードの読み方は以下の通りです。

  • for x in range(10): x0~9まで順次代入する
  • x**2: xに代入された数値の二乗した数値をリストに加える

squaresの内容は以下となります。

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

続いて、if文を加えた例を考えてみましょう。

0から9までの数値の中から「偶数だけ」を取り出し、その値に2乗してリストに加えたい場合は以下になります。

squares = [x**2 for x in range(10) if x % 2 == 0]

読み方は以下の通りです。

  • for x in range(10): 0から9までが順にxに入る
  • if x % 2 == 0: xの値が2で割り切れれば次に進む
  • x**2: xを二乗してリストの要素に加える

初見だとちょっと読むのが大変ですが、このような複雑なロジックをワンライナーで書けるのは大きな魅力です。

複数の条件を持つリスト内包表記の書き方

複数条件を持つ内包表記の場合は、if節内にandorなどを加えます。

イメージが湧きやすいように、具体例を挙げて解説します。

andを使った具体例

0から99までの数字のうち、3で割り切れ、かつ(and5より大きい数の二乗をリストとして生成したい場合は以下になります。

result = [x**2 for x in range(100) if x % 3 == 0 and x > 5]

orを使った例

0から99までの数で、2で割り切れるか、または(or9で割り切れる数をリストに入れる場合は以下になります。

result = [x for x in range(100) if x % 2 == 0 or x % 9 == 0]

辞書内包表記の書き方

リスト内包表記の辞書版が「辞書内包表記」です。

特定のキーとバリューを持つ新たな辞書を作成する方法になります。

  • 辞書内包表記の基本的な書き方
  • 条件を加えた辞書内包表記

順番にレベルアップしていきますので、順に解説していきます。

辞書内包表記の基本的な書き方

リストと同様、辞書にも内包表記があります。

基本的な書き方は以下の通り。

new_dict = {key_expression: value_expression for item in iterable if condition}

例として、ある文字列に含まれる各文字の出現回数を数えるものを示します。

text = "hello"
char_count = {char: text.count(char) for char in text}

読み方としては、以下のようになります。

  • for char in text: 文字列 “hello” を1文字ずつcharに代入
  • char: text.count(char): それぞれの文字 char をキーとして、その文字が文字列 “hello” に出現する回数をバリューとする辞書を作成

実行すると、以下のような出力結果が得られます。

{'h': 1, 'e': 1, 'l': 2, 'o': 1}

条件を加えた辞書内包表記

先ほどの例ではif節なしのシンプルなものでしたので、ここでは条件をつけた内包表記の書き方をご紹介します。

特定の条件を満たす要素のみを含む辞書を作成

# 0から9までの数字の中で、奇数のみをキーとし、その平方を値とする辞書を作成
odd_squares = {x: x**2 for x in range(10) if x % 2 != 0}

0から9の中で「奇数のみの値」をキー、「それぞれの数値の二乗」をバリューとして辞書に格納します。

例2: 文字列内の特定の文字をカウントして辞書を作成

text = "hello world"
# text から母音のみを抽出し、それぞれの出現回数をカウント
vowel_counts = {char: text.count(char) for char in text if char in "aiueo"}

textのうち「母音に含まれる文字」をキー、「その出現回数」をバリューとして辞書に格納します。

内包表記のベストプラクティス

ここでは内包表記について、以下のようなアドバンス的な内容を解説します。

  • 内包表記のパフォーマンスについて
  • 内包表記のベストプラクティスについて

それぞれ解説していきます。

内包表記のパフォーマンスについて

通常、内包表記はforループより高速です。

これは Python の内部最適化によるもので、内包表記のコードは C 言語レベルで直接実行されるために関数呼び出しのオーバーヘッドが減ります。

特にリストや辞書の生成では、内包表記を使うと明らかにパフォーマンスが上がる。

ただし、複雑な内包表記はコードが非常に読みづらくなってしまうので、いくらパフォーマンスが上がったとしても可読性を重視してforループで書くべきシーンは多くあります。

内包表記のベストプラクティスについて

内包表記を上手に使うため、以下の点に注意していきましょう。

  • 単純なロジックに限定して使用
  • 可読性を重視する

一つずつ、解説していきます。

単純なロジックに限定して使用

内包表記は「単一のループ」と「簡単な条件」に向いた表記方法です。

ネストされたループや複雑な条件式を含む場合には、通常のforループの方が断然読みやすいくなります。

無理して内包表記とするのではなく、保守性を考えてforループを使うべきこともあると理解しておきましょう。

可読性を重視する

内包表記を覚えると、なんでもかんでも内包表記を使いたくなるものです。

ところが、先にも触れたように複雑なロジックを内包表記に落とし込もうとすると可読性が著しく損なわれます。

そのような場合にはそもそもfor文を使ってコードを組むか、コメントを加えることで後から読んでも意味がわかるように配慮しておくことが重要です。

内包表記を理解して、Pythonスキルをワンランクあげよう!

以上の内容をご理解いただければ、内包表記の基礎はバッチリだと思います。

初見ではとっつきにくいかと思いますが、少しずつ手を動かして書いていけば必ず「書ける」「読める」ようになります。

ぜひ、めげずにトライしてみてくださいね。

当ブログでは他にも Python 関連の記事をアップしていますので、よろしければ合わせてご覧になってみてください!

» 参考:CFXLOG – Python に関する記事一覧

この記事が気に入ったら
フォローしてね!

シェア・記事の保存はこちら!

この記事を書いた人

karo@プログラマのアバター karo@プログラマ プログラマ

「書くことで人の役にたつ」をモットーに活動中。
本職はプログラマで、Pythonが得意。
基本情報技術者試験合格。

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)