Pythonの内包表記

プログラミング

プログラムはできるだけシンプルに分かりやすく記述することで、バグや認識違いを少なくすることができます。

Pythonの内包表記は、プログラムをシンプルに記述することができる手法の1つです。

本記事では、Pythonの内包表記について解説します。

記事内に記載しているプログラムは、Python3.6.8を使って動作確認をしています。

Pythonの内包表記

Pythonの内包表記について、以下の内容を解説します。

  • Pythonの内包表記とは
  • リスト内包表記
  • タプル内包表記
  • 集合内包表記
  • 辞書内包表記
  • ジェネレータ式

Pythonの内包表記とは

Pythonの内包表記とは、リストや辞書などのイテラブルオブジェクトを簡潔に生成する記法です。
基本的な書き方は、以下のようになります。

  • [式 for 変数 in イテラブルオブジェクト]
  • [式 for 変数 in イテラブルオブジェクト if 条件式]

使い所としては、以下のような場面となります。

  • あるリストや辞書の要素に対して、操作を行った結果を要素にした新たなリストや辞書を作る時
  • あるリストや辞書の要素の中で、条件を満たす要素を取り出した新たなリストや辞書を作る時

ループの中で行っていた処理を内包表記にすることで、シンプルに記述することができるようになります。

リスト内包表記

基本形

リストの内包表記との違いがわかりやすいように、まずは通常の記述方法が以下となります。

r = []
for i in range(10):
    r.append(i ** 2)
print(r) # -> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

上記のプログラムでは、空のリストrにループの中でインデックスの2乗の値を追加しています。
これを内包表記を用いると以下になります。

r = [i ** 2 for i in range(10)]
print(r) # -> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

ループで値を追加する部分を1行で表すことができて、シンプルな記述になりました。

後置ifを使った内包表記

後置ifを使って、リストの値に条件を設定することで、条件に合わない要素をフィルタリングするような操作を行うことができます。

l = [91, 88, 99, 70, 1, 100, 0]
r = [score for score in l if score >= 90]
print(r) # -> [91, 99, 100]

上記のプログラムでは、リストから90以上の要素を抽出した新たなリストを作成しています。

三項演算子を使った内包表記

内包表記の「式」部分には、様々な処理を行うことができます。
例えば、if~elseの条件式を記述して、リストの要素に条件をつけた処理を行うことができます。

l = [91, 88, 99, 70, 1, 100, 0]
r = ["合格" if score >= 90 else "不合格" for score in l]
print(r) # -> ['合格', '不合格', '合格', '不合格', '不合格', '合格', '不合格']

上記のプログラムでは、90以上の要素は「合格」、90未満の要素は「不合格」を持つ新たなリストを作成しています。

ネストした内包表記

内包表記のforをネストさせることで、2次元配列のリストを作ることができます。

r = [[i, j] for i in range(2) for j in range(2)]
print(r) # -> [[0, 0], [0, 1], [1, 0], [1, 1]]

例えば以下のような行列を作ることも可能です。

limit = 4
r = [[(j+1)+i*limit for j in range(limit)] for i in range(3)]
print(r) # -> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]

また、逆に2次元配列を1次元配列にバラすこともできます。

l = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12]
]
r = [j for inner in l for j in inner]
print(r) # -> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

タプル内包表記

タプルにおいても内包表記を用いることができます。
tuple()の括弧内に内包表記を記述します。

r = tuple(i ** 2 for i in range(10))
print(r) # -> (0, 1, 4, 9, 16, 25, 36, 49, 64, 81)

集合内包表記

集合(Set)においても内包表記を用いることができます。
{}内に内包表記を記述します。

r = {i ** 2 for i in range(10)}
print(r) # -> {0, 1, 64, 4, 36, 9, 16, 49, 81, 25}

辞書内包表記

辞書においても内包表記を用いることができます。
{}内にkeyとvalueを指定して内包表記を記述します。

l = ["hoge", "foo", "bar", "baz"]
r = {s : len(s) for s in l}
print(r) # -> {'hoge': 4, 'foo': 3, 'bar': 3, 'baz': 3}

zipを用いることで、別々のリストから内包表記で辞書を作成することもできます。

index = [1, 2, 3, 4]
l = ["hoge", "foo", "bar", "baz"]
r = {i : s for i, s in zip(index, l)}
print(r) # -> {1: 'hoge', 2: 'foo', 3: 'bar', 4: 'baz'}

ジェネレータ式

内包表記は記述がシンプルで分かりやすいのですが、入力する要素数が大きいと一度にメモリ展開するため、コストが高くなるデメリットがあります。
この問題に対して、ジェネレータを使うと、要素を1つ1つ生成するため、メモリの消費を抑えることができます。

ジェネレータ式は、内包表記に対して、()で括ることで作成できます。

g = (i ** 2 for i in range(10))
print(type(g))
    for n in g:
print(n)

上記のプログラムでは、内包表記を括弧で括って、ジェネレータ式を変数gに代入しています。
gに対してループで要素を取り出すと、内包表記で作成したリストの要素であることが確認できます。

上記のプログラムを実行した結果は以下となります。

<class 'generator'>
0
1
4
9
16
25
36
49
64
81

後置ifを使ったジェネレータ式を作成することも可能です。

l = [91, 88, 99, 70, 1, 100, 0]
g = (score for score in l if score >= 90)
    for n in g:
print(n)

上記のプログラムを実行した結果は以下となります。

91
99
100

まとめ

Pythonの内包表記についてまとめると以下になります。

  • Pythonの内包表記とは、リストや辞書などのイテラブルオブジェクトを簡潔に生成する記法である。
  • 内包表記には、後置ifによる要素のフィルタリングや、三項演算子による条件判定など様々な処理を記述することができる。
  • ジェネレータ式を使うと内包表記の処理コストを節約することができる。

リストに対してループで値を抽出するような操作を行う場合には、内包表記を使ってみてほしいと思います。

 

今回はPythonの内包表記を解説しました。

以上、参考になれば幸いです。

コメント

タイトルとURLをコピーしました