内包表記 (Comprehension)
Python には リスト や ディクショナリ などのイテラブルオブジェクトの各要素を操作して、新しいイテラブルオブジェクトを作り出す 内包表記 (Comprehension) とよばれる記法が備えられています。
リスト内包表記
list オブジェクトの操作は案外面倒なものです。たとえば、リストのすべての要素に 1 を加えた新しいリストを作ろうとすれば、for文を使って次のようなコードを書く必要があります。
# PYTHON_LIST_COMPREHENSION
# In[1]
# リスト型データを定義
num_list = [1, 2, 3, 4, 5]
# 空白のリストを用意します
new_list = []
# リストの各要素に1を加える
for x in num_list:
new_list.append(x + 1)
print(new_list)
[2, 3, 4, 5, 6]
上のサンプルにおける for 文のコードブロックでは、リストの各要素に対する操作が行われています。プログラミングに慣れた人なら、たったこれだけのためにループ処理の中で何度も繰り返し関数を呼び出されているのを見るだけで、直感的に実行速度の低下を感じて「うんざり」してしまうかもしれません。しかし、Python にはこの種の処理を簡潔に記述するために リスト内包表記 が備わっています。
# In[2]
# 内包表記を使ってリストの各要素に1を加える
new_list = [x + 1 for x in num_list]
print(new_list)
[2, 3, 4, 5, 6]
上のコードではリストの各要素に 1 を加えた新しいリストを作る処理を
new_list = [x + 1 for x in num_list]
という1行のコードにまとめています。リスト内包表記の基本形は
です。x は繰り返し変数なので、i や k など好きな文字を使ってください。もとのイテラブルオブジェクトは必ずしもリスト型である必要はありませんが、戻り値はリストになります。もとのイテラブルオブジェクトから要素を順に取り出して x に入れて、指定した処理を施してから、新しいリストの要素としてゆきます。
リストの各要素を 2 乗してすべて足し合わせてみましょう。これも内包表記を用いると簡潔に表現できます。
# In[3]
# 内包表記で平方和を計算
sq = sum([x ** 2 for x in num_list])
print(sq)
55
上のコードでは、元のリストの要素をすべて 2 乗した要素をもつ新しいリストを作ってから、sum 関数でそれらの要素をすべて足し合わせることによって、平方和の計算を行なっています。
今度は内包表記の基本形の後ろに条件式を添えてみます。
この形式で記述した場合、if のあとに添えられた条件式を満たしている場合に限って、x に処理が施されて新しいリストに追加されます。言い換えると、もとのリストから取り出された要素が条件を満たしていない場合、その要素は破棄されることになります。
簡単な例として、元のリストから 100 を超える要素だけを取り出すコードを書いてみます。
# In[4]
# 条件式を含むリスト内包表記[1]
# リスト型データを定義
num_list = [78, 155, 103, 21, 59, 117]
# 内包表記で100を超える要素だけを取り出す
new_list = [x for x in num_list if x > 100]
print(new_list)
[155, 103, 117]
次はもう少し複雑な条件式です。リストの要素から "p" というアルファベットを含む単語だけを抜き出します。
# In[5]
# 条件式を含むリスト内包表記[2]
# フルーツのリスト
fruits = ["apple", "orange", "strawberry", "pear", "plum"]
# 内包表記で"p"を含む要素だけを取り出す
new_fruits = [x for x in fruits if x.find("p") != -1]
print(new_fruits)
['apple', 'pear', 'plum']
条件式のところで find メソッドを用いています。find メソッドは対象とする文字列の中に指定文字がみつからなければ「-1」を返してきます。「!=」は「等しくない」という意味の比較演算子です。つまり「 x が -1 に等しくないならば、それは "p" という文字を含むのだから要素に加えなさい」ということです。
![]() |

ディクショナリ内包表記
キーと値のペアを要素にもつディクショナリの内包表記は、リスト内包表記よりも少し複雑です。基本的な書き方は次のようになります。
items メソッドを使うことによって、キーと値の両方に対して処理を行なって新しい辞書を作ります。x, y はそれぞれキーと値が入る変数です。
書籍の表題をキー、税抜価格を値とするディクショナリを定義して、書籍の表題と税込価格のディクショナリを作ります。この記事を執筆している 2018 年現在の消費税は 8% (2019 年に 10 % となる予定) なので、税抜価格を 1.08 倍にして小数点を捨てれば税込価格が得られます。
# PYTHON_DICTIONARY_COMPREHENSION
# In[1]
# ディクショナリ内包表記[1]
# 書籍と税抜き価格のディクショナリ
# _ex はtax excluded(税抜)を意味する添字
book_ex = {"Pythonスタートブック":2500,\
"Pythonの絵本":1780,\
"入門Python3":3700}
# 内包表記で書籍と税込み価格のディクショナリを作成
# _inはtax included(税込み)を意味する添字
book_in = {x:int(y*1.08) for x, y in book_ex.items()}
print(book_in)
{'Pythonスタートブック': 2700, 'Pythonの絵本': 1922, '入門Python3': 3996}
処理するのは値のほうなので、x には何も手を加えておらず、もとの辞書のキー(税抜価格)のみが書き換えられて新しい辞書が作られています。
ディクショナリ内包表記を使うと簡単にキーと値を入れ替えることができます。以下のサンプルコードでは「書籍:発行元(出版社)」の辞書から「発行元(出版社):書籍」の辞書を作ります。
# In[2]
# ディクショナリ内包表記[2]
# 書籍と発行元(出版社)のディクショナリを定義
# _pub は publisher の略
book_pub = {"詳細! Python3入門ノート":"ソーテック社",\
"かんたんPython":"技術評論社",\
"スラスラわかるPython":"翔泳社"}
# 内包表記でキーと値を入れ替える
pub_book = {p:b for b,p in book_pub.items()}
pub_book
{'ソーテック社': '詳細! Python3入門ノート', '技術評論社': 'かんたんPython', '翔泳社': 'スラスラわかるPython'}
内包表記のコード
pub_book = {y:x for x,y in book_pub.items()}
において、x は書籍、y は発行元に対応する変数ですが、for の前の処理文が「 y:x 」と逆順になっています。つまり、もとの辞書の値をキー、キーを値にするという処理が行われて、キーと値の交換が行われているのです。
set内包表記
set とリストは非常によく似た性質をもつオブジェクトなので、set 内包表記はリスト内包表記とほぼ同じような記述で使えます。
とはいえ、せっかくですから、set オブジェクトならではの「要素の重複を取り除く」という性質を生かしたサンプルコードを書いてみます。最初文字列を定義して、その中で使われているアルファベットを重複なしに小文字で列挙してみます。
# PYTHON_SET_COMPREHENSION
# In[1]
# set内包表記
# 文字列を定義
my_string = "Learn Python in One Day and Learn It Well"
# 内包表記で文字列を1文字ずつ分割して重複は省く
# ただし空白は除く
my_words = {x.lower() for x in my_string if x != ' '}
my_words
{'a', 'd', 'e', 'h', 'i', 'l', 'n', 'o', 'p', 'r', 't', 'w', 'y'}
文字列は1文字ずつにインデックスが割り当てられたオブジェクトなので、それを内包表記で1文字ずつ取り出す操作を行なうと、文字列はバラバラにされて、1文字を1要素として set の中に格納されていきます。
内包表記は速度でも有利です
内包表記を応用すると、複数の変数を組み込んで、2 次元や 3 次元の配列をたった1行のコードで生成したりすることもできるようになります。
しかし、内包表記はコードをすっきりとまとめるためだけに存在するのではなく、処理速度を大幅に向上させるという利点をもちます。for 文などを使ってイテラブルオブジェクトの要素を操作する場合には、どうしてもコードブロックで append 関数などを呼び出さなくてはなりません。一方で内包表記はリストの要素を直接操作する記法なので、大きなデータを扱う場合には速度面で圧倒的に有利です。
内包表記は何か特別で高級なことをやろうという記法ではなく、むしろその逆で、関数などを使わずに操作をできるだけ単純化させようと考えて設計されているのです。
分かりやすいサイトで大変助かっております。
以下のコードを実行すると、エラーがでました。
「fruit_list」を「fruits」に変えるとうまくいきました。
ご確認ください。
========================================
# In[5]
# 条件式を含むリスト内包表記[2]
# フルーツのリスト
fruits = [“apple”, “orange”, “strawberry”, “pear”, “plum”]
# 内包表記で”p”を含む要素だけを取り出す
new_fruits = [x for x in fruit_list if x.find(“p”) != -1]
print(new_fruits)
申し訳ありません。
記事は訂正させていただきました。
大変助かりました。
ありがとうございます。