- 内包表記って書き方がよくわからない…
- コードを見ても意味がわからない!
このような疑問にお答えします。
Python では内包表記がごく簡単に書けるため、Python を象徴するものとして挙げられることが多いです。(他の言語では存在はしている)
この内包表記ですが、簡潔に書ける一方で初学者は以下のように混乱しがちです。
- 内包表記を組み立てられない
- 内包表記を読んで意味を理解できない
これらは、内包表記の書き方をしっかりと理解すれば解決できます。
本記事では内包表記について丁寧に解説していきますので、不安がある方はぜひじっくりと読み進めてみてください!
内包表記の概略を理解しよう!
内包表記は、新たにリストや辞書などを生成するための方法です。
for
ループとif
ステートメントを含むコードを一行(ワンライナー)で書けるのが魅力。
例えば、次のような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)
:x
に0
~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
節内にand
やor
などを加えます。
イメージが湧きやすいように、具体例を挙げて解説します。
and
を使った具体例
0
から99
までの数字のうち、3
で割り切れ、かつ(and
)5
より大きい数の二乗をリストとして生成したい場合は以下になります。
result = [x**2 for x in range(100) if x % 3 == 0 and x > 5]
orを使った例
0
から99
までの数で、2
で割り切れるか、または(or
)9
で割り切れる数をリストに入れる場合は以下になります。
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 関連の記事をアップしていますので、よろしければ合わせてご覧になってみてください!
コメント