内包表記によるショートコーディング
7.2 内包表記によるショートコーディング
続いて内包表記について紹介します。内包表記はfor文が組み込まれているPythonの書式の1種であり、特定の条件を満たす値の配列を扱いたい場合など、より複雑な配列を扱う際に便利です。
複数行必要なコードを1行にまとめることができるので、わかりやすく、かつ処理速度の向上に繋がります。以下で内包表記について一つずつ確認していきましょう。
7.2.1 リスト内包表記
まずリスト内包表記とは、以下のような書式のものを意味します。
書式:リスト内包表記
[仮変数を用いた式 for 仮変数 in イテラブルオブジェクト]
リストやタプルなどの配列の各要素が仮変数に格納され、各要素の値が「仮変数を用いた式」に代入され、式への代入結果を要素としたリストが返されます。
そのためリスト内包表記そのものを代入した、変数はリスト型の変数になります。
凡例
実行結果
2 4 6 8
range(1,5)には「1,2,3,4」の各値が格納されており、各値を2倍にした値が、変数numbersの各要素として格納されます。
図 7.2.1:リスト内包表記について
7.2.2 辞書内包表記
続いて辞書内包表記とは、以下のような書式のものを意味します。
書式:辞書内包表記
{キーのための式: 値のための式 for 仮変数 in イテラブルオブジェクト}
辞書では各要素につき、キーと値の2つが必要になりますので、キーと値、それぞれの式を設けます。リスト内包表記と同様、リストやタプルなどの配列の各要素が仮変数に格納され、各要素の値が、それぞれの式に代入され、その結果を要素とした辞書が返されます。
そのため辞書内包表記そのものを代入した、変数は辞書型の変数になります。
またイテラブルオブジェクトには、zip関数を使用されることが多く、その場合、zip関数の各要素を取り出すために、仮変数が二つ使用されます。
凡例
実行結果
{'鈴木': '神田', '佐藤': '東京', '田中': '新宿'}
zip関数を使用しているため、for文を介してnames、stationsの各要素が取り出されます。namesの各要素が仮変数name、stationsの各要素が仮変数stationに代入されるため、辞書型変数addressの、各要素のキーはname、値にはstationが格納されます。
凡例をイメージで表すと以下の図のようになります。
図 7.2.2:辞書内包表記
7.2.3 if文を使ったリスト内包表記
リスト内包表記は、if文を使って条件を満たす要素だけを含むリストを作ることができます。
1. 一般的なif文を使ったリスト内包表記
if文を使用したリスト内包表記の書式は以下の通りになります。
書式:if文を使ったリスト内包表記
[仮変数を用いた式 for 仮変数 in イテラブルオブジェクト if 条件式]
条件式を満たす(true)、イテラブルオブジェクトの要素だけが返され、その要素の各値が「仮変数を用いた式」に代入され、その代入結果を各要素としたリストが返されます。
条件式に使用される仮変数は、for文、仮変数を用いた式と同じものを使用します。
凡例
numbers = [i for i in range(1,11) if i%2 == 0] for i in numbers: print(i)
実行結果
2 4 6 8 10
range(1,11)には1~10の各値が格納されてますが、「if i % 2 == 0」を満たす要素だけが返されます。
2で割った余りが0の要素(偶数)だけが条件を満たすので、「2,4,6,8,10」がリスト型変数numbersに格納されます。
凡例を図で表すと以下の通りになります。
図 7.2.3:if文を使ったリスト内包表記について
2. 三項演算子を含めた(if-else的な処理をする)リスト内包表記
三項演算子を使うことで、条件を満たす場合と満たさない場合で、代入先の変数に返す各要素の値を分けることができます。
三項演算子とは、if else文を一行で記述する際に用いられる書式であり、書式は以下の通りになります。
書式: 三項演算子
trueの処理 if 条件式 else falseの処理
通常のif else文と三項演算子との比較を図にまとめると以下の通りになります。
図 7.2.4: 三項演算子と通常のif else文の比較
凡例
i = 3 print('偶数') if i%2 == 0 else print('奇数')
実行結果
奇数
書式: 三項演算子を使ったリスト内包表記
上記を踏まえた上で、三項演算子を使ったリスト内包表記の書式を表すと、以下の通りになります。
[trueの式 if 条件式 else falseの式 for 仮変数 in イテラブルオブジェクト]
凡例
numbers = [i if i%2 == 0 else '奇数' for i in range(1,6)] for i in numbers: print(i)
実行結果
奇数 2 奇数 4 奇数
range(1,6)には1~5の各値が格納されてます。
その中から「if i % 2 == 0」の条件式(偶数である)を満たす要素は、そのままの値がnumbersに格納され、満たさない要素は’奇数’という文字列が要素として格納されます。
図 7.2.5:三項演算子を使ったリスト内包表記について
7.2.4 ジェネレータ内包表記
内包表記でジェネレータを表現することもできます。ジェネレータを表す内包表記をジェネレータ内包表記と呼び、書式は以下の通りです。
書式:ジェネレータ内包表記
(仮変数を用いた式 for 仮変数 in イテラブルオブジェクト)
書式はリスト内包表記とほとんど同じですが、角括弧[]ではなく丸括弧()を使用します。使用方法や仕組みもリスト内包表記とほとんど同じですが、ジェネレータ内包表記が代入された変数は、イテレータになるので「__next__メソッド」が含まれておりnext関数を使用することで、参照する値を次にずらすことができます。
7.2.5 ジェネレータ内包表記を使ったプログラム
ではジェネレータ内包表記を使ったプログラムを確認していきましょう。
ソース・フォルダー: /Desktop/Python基礎講座
ファイル名: 第7章.ipynb
アクセスURL: http://localhost:8888/notebooks/Desktop/Python基礎講座/第7章.ipynb
numbers = (i*2 for i in range(1,5)) next(numbers) for i in numbers: print(i)
実行結果
4 6 8
解説
1行目でrange(1,5)には「1,2,3,4」の各値が格納されており、各値を2倍にした値が、イテレータのnumbersの各要素として格納されます。
numbers = (i*2 for i in range(1,5))
1行目のイメージを図にまとめると以下の通りになります。
図 7.2.6:ジェネレータ内包表記
3行目でnumbersを引数にnext関数を使用してます。numbersはイテレータですのでnext関数を使用すると、値を参照する際、使用前と比べて次の値が参照されるようになります。
そのため5、6行目でfor文を介してnumbersの値を取り出すと、上記のような実行結果になります。
next(numbers) for i in numbers: print(i)
5、6行目のイメージを図にまとめると以下の通りです。
図 7.2.7: イテレータnext関数
ポイント
- リスト内包表記を使うとfor文や式を介して表す必要があるリストが1行で表現できる。
- 辞書内包表記を使うとfor文や式を介して表す必要がある辞書が1行で表現できる。
- if文や三項演算子を介して条件別に異なる値が格納されるリスト内包表記が表現できる。
- ジェネレータ内包表記を介してイテレータ(ジェネレータ)を生成できる。