Pythonでの内包表記について学習したのでここに記録として残す。
Pythonの内包表記とは、簡潔にリストや辞書を作成することができる機能でコード文が短くメモリ処理を少なくすることができるかつ、可読性も高めることができる。
内包表記の種類
内包表記には、
リスト内包表記、辞書内包表記、集合内包表記、ジェネレータ式がある
リスト内包表記
t = (1,2,3,4,5)
#通常処理
r = []
for i in t:
if i % 2 == 0:
r.append(i)
print(r)
#内包表記
r = [i for i in t if i % 2 == 0]
print(r)
上記コードのように空のリストを作成して、タプルのt,t2をリストの中に格納して,偶数のみをリストに核の黄酒流処理を書くときに、for文でも処理を行えるが(#通常処理)、内包表記を行うと一文で書くことができる。
基本構文としては以下のようになる。
[式 for 変数 in イテラブル if 条件]
処理としては、r=[]に二つ目のiにfor文でtを順番に代入していき、そのiを2で割ったものの余りが0の時に一つ目のiに代入され、rのリストが完成する。
また、ネストした内包表記も行うことができる。
t = (1,2,3,4,5)
t2 = (5,6,7,8,9,10)
for i in t: #通常処理
for j in t2:
r.append(i*j)
print(r)
r = [ i * j for i in t for j in t2 ]#内包表記
print(r)
この内包表この処理の場合、rの中のforから処理を行い、iにt,jにはt2をそれぞれ代入していく最終的にfor文手前の掛け算が行われ、出力としては、通常処理と同じものになる。
[5, 6, 7, 8, 9, 10, 10, 12, 14, 16, 18, 20, 15, 18, 21, 24, 27, 30, 20, 24, 28, 32, 36, 40, 25, 30, 35, 40, 45, 50]
辞書内包表記
w = ["mon","tue","wed"]
f = ["coffee","milk","water"]
d = {}
for x , y in zip(w,f):
d[x] = y
print(d)
d= {x:y for x,y in zip(w,f)}
print(d)
空のリストdを作り、for文で繰り返し処理を行う場合、zip関数を用いて、変数wとfのペアをタプルで作る。その後forループでペアを一つずつ取り出し、xとyにそれぞれ代入していく、dの中のxをキー、yを値として、dの辞書をプリントする。
内包表記では、キーと値のセットを作らなくても、x:yで認識され、for文で繰り返し処理を行いxとyにそれぞれw、fが代入され、キーと値の処理がされて出力される。
{'mon': 'coffee', 'tue': 'milk', 'wed': 'water'}
集合内包表記
s = set()
for i in range(10): #通常処理
if i % 2 == 0:
s.add(i)
print(s)
s={i for i in range(10) if i % 2 ==0} #内包表記
print(s)
set()とは重複のないデータを管理するデータ型である。
リストやタプルとは違い、同じデータを格納はできない。
add()は新しい要素を追加する関数でsetと組み合わせてよく使われる。
すでに存在する要素を追加してもその要素は無視される。
この処理は、forループで0から9までの数字をiに代入していき、偶数のみをadd()を使いs代入していく。
内包表記では、addを使わずに、sをset()と定義しているため、forループを描くことで、重複するデータを排除し、出力される。
最初に定義した、変数iを飛び越えて、for文から先に処理を行い、最終的な処理結果を、一番はじめの変数に要素が格納され、出力される。
{0, 2, 4, 6, 8}
ジェネレーター内包表記
ジェネレーターとは、() を使ってジェネレーターオブジェクトを作成し、必要なときに1つずつ値を取り出せるのが特徴。リストやタプルと違い、要素全ての処理をせずnextやyieldで一つずつ処理をされるので、メモリ効率が良い。
試しにジェネレーターを書いてみる。
def g():
for i in range(10):
yield i
g=g()
print(next(g))
0
iに9までの数字を格納したのちにyieldで一つずつ要素を取り出している処理を行い、変数gに格納する。
それをprintで呼び出し、nextで出力すると、一番はじめの要素0が取り出され出力される。
これを内包表記でやってみる。
g= (i for i in range(10)if i % 2 == 0)
print(type(g))
print(next(g))
for x in g :
print(x)
タプルと間違えやすいためtypeを出力してある。
また、forループで全ての要素を最後に取り出しているため、後にnextで呼び出してもエラーになるため注意。
<class 'generator'>
0
2
4
6
8
基本的に他の内包処理と書き方は同じだが、一度取り出した要素は使えないため、for文の後に要素を取り出そうとしても、取り出せない。
通常通りジェネレーターを書くときと違って、yieldを使い関数を定義しなくてもいい。
処理としては、forループで9までの数字をiに格納し偶数のみをiにTrueとして格納する。
print(next)で出力し0を出力。
その後、forループを使うと自動でnext()を呼び出しプログラムが終了する。
※タプルとして呼び出したい時はg=の後にtupleと宣言する
まとめ
リスト内包表記 [式 for 変数 in イテラブル if 条件] list
辞書内包表記 {キー: 値 for 変数 in イテラブル if 条件} dict
セット内包表記 {式 for 変数 in イテラブル if 条件} set
ジェネレータ式 (式 for 変数 in イテラブル if 条件) generator