Pythonの内包表記について見ていきましょう。
内包表記を使うとリストや辞書などのイテレータのデータ構造をコンパクトに書くことができます。ブロックコードでイテレータを生成するコードを作るよりも、とてもシンプルな表記になります。数行での処理を1行で書くことができるので、処理スピード上も有利と言われています。
この内包表記を使ってコードを書ける人は、Pythonの全くの初心者では無いなと思われるレベルでもあるでしょう。
リスト内包表記、辞書内包表記、集合内包表記、ジェネレータ内包表記といった書き方があります。順に見ていきましょう。
リスト内包表記
まずリスト内包表記からやって行きましょう。
最初にこれまでの知識を使ってリストを作るコードを書いてみます。次のようなコードを書いてみましょう。
my_list = []
for i in range(1, 10):
my_list.append(i)
空のリストを用意して、for文を使って1から9までの範囲で1つずつrange()関数で取り出し、append()関数を使ってリストの中に追加しているというコードになっています。
これを実行するとこうなります。
要素を持ったリストができているのがわかりますね。
この3行のコードを内包表記を使って書けば、1行で書くことができます。
[リストに追加する要素 for 要素 in イテレータオブジェクト]という形で書きますが、具体的に書いた方がわかり易いですね。
上のコード内包表記で書けばこのようになります。
my_list = [i for i in range(1, 10)]
このような書き方をリスト内包表記と言います。
実行すると同じ結果が得られます。
リスト内包表記の特徴的な書き方がよくわかると思います。
さて、これらのコードをもうちょっと触ってみましょう。最初のコードを偶数だけ取り出すコードに変更してみます。
my_list = []
for i in range(1, 10):
if i % 2 == 0:
my_list.append(i)
for文で取り出した要素を、if文を使って偶数かどうかを判定しています。偶数は2で割った余りがゼロとなる数値という条件を与えていますね。この条件を満たしたものを、リストに加えています。
コードを実行してみましょう。
偶数だけ含まれたリストになっているのがわかります。
これをリスト内包表記で書くとどうなるでしょうか。
[リストに追加する要素 for 要素 in イテレータオブジェクト if 条件]という形になりますが、具体的に見た方がわかりやすいですね。
コードはこうなります。
my_list = [i for i in range(1, 10) if i % 2 == 0]
取り出した値をif文で判定して、リストに入れる形になっています。上のfor文の後ろにif文の条件文を書いている形です。
実行するとこうなります。
同じリストが出力されています。
もう1つ見ておきましょう。
リスト内包表記は、for文を複数入れて使うこともできます。
まず、次のような2つタプルからそれぞれをfor文で取り出しながら、掛け算した値をリストにするというコードを考えてみます。
こんなコードになるはずです。
t1 = (2, 4, 6, 8)
t2 = (1, 3, 5, 7)
my_list = []
for i in t1:
for j in t2:
my_list.append(i * j)
print(my_list)
1つめのタプルから要素を取り出し、それをもう1つのタプルの要素にそれぞれ掛け算してリストに加えていくことを繰り返しているコードです。
実行するとこうなります。(ファイル名をcomprehention.pyにしてAtomで実行しています)
2つのタプルの要素をそれぞれ掛け算した値のリストになっているのがわかります。
このコードをリスト内包表記で書いてみるとこんなコードになります。
t1 = (2, 4, 6, 8)
t2 = (1, 3, 5, 7)
my_list = [i * j for i in t1 for j in t2]
print(my_list)
forループの後ろにさらにforループ処理を書くことでネストした処理をすることができています。
実行してみましょう。
同様の結果が得られています。
このように、リスト内包表記を使えば、複数行にわたるリストを生成するコードを1行で書くことができるので、コードがスッキリするわけですが、上のforのネストをいくつも重ねると今度は逆に読みにくくなります。上の例くらいの反復処理でとどめておくのが妥当だと思います。
辞書内包表記
次は辞書内包表記を見て行きましょう。
{キー: 値 for 要素 in イテレータオブジェクト}という形になりますが、これも具体的に見ていく方がわかり易いでしょう。
次のようなコードで、まずこれまで知識で辞書型データを作ってみます。
meisters = ["Setsuna", "Lockon", "Allelujah", "Tieria"]
gundams = ["EXIA", "DYNAMES", "KYRIOS", "VIRTUE"]
gundam_dict = {}
for x, y in zip(meisters, gundams):
gundam_dict[x] = y
print(gundam_dict)
例によってガンダム00を使っています。2つのそれぞれ対応するリストを用意します。空の辞書を用意して、2つのリストからzip()関数を使って並列にfor文でそれぞれ取り出し、辞書のキーに指定して値を入れているコードになっています。
このコードを実行してみましょう。
2つのリストに対応した辞書型データができています。
これを辞書内包表記で書き換えるとこうなります。
meisters = ["Setsuna", "Lockon", "Allelujah", "Tieria"]
gundams = ["EXIA", "DYNAMES", "KYRIOS", "VIRTUE"]
gundam_dict = {x: y for x, y in zip(meisters, gundams)}
print(gundam_dict)
リスト内包表記と要領はほぼ一緒ですね。辞書に入れるキーと値をコロン(:)を間に入れて用意し、それぞれの要素をfor文で取り出しています。
実行すると、こうなります。
同様の辞書が作成されています。
リスト内包表記は角括弧[]で作り、辞書内包表記は波括弧{}で作ってキーと値を用意するという違いはありますが、同じように書けることがわかると思います。
集合内包表記
集合内包表記もリスト内包表記と同様な操作で書くことができます。
{集合に追加す要素 for 要素 in イテレータオブジェクト}という形です。
集合なので波括弧{}で書くという違いだけです。
ここでも同様に、これまでのコードの書き方と内包表記の書き方の両方を書いてみます。
s = set()
for i in range(5):
s.add(i)
print(s)
実行するとこうなります。
集合が作られています。
これを集合内包表記で書くとこうなります。
s = {i for i in range(5)}
print(s)
実行するとこうなります。
同様の結果が得られています。
この集合内包表記も、リスト内包表記でやったのと同じように、後ろにif文を続けて条件を判定させ偶数だけの集合を作るというようなこともできます。
ジェネレータ内包表記
最後にジェネレータ内包表記を見ていきましょう。
ジェネレータとはなんぞやとPython初心者だとなってしまいそうですが、ちょっと前にこちらで学んだので確認しておきましょう。
まずジェネレータ関数を使ったコードを書いてみます。
gundam_list = ["EXIA","DYNAMES","KYRIOS","VIRTUE"]
def gundams():
for gundam in gundam_list:
yield gundam
g = gundams()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
いつものガンダム00ですw そろそろ違うネタを扱いところですね。
リストの中からfor文で順に値を取り出すジェネレータ関数を定義しています。yieldで値を返しているので、呼び出しにnext()を使って順番に1つずつ表示する処理をしています。
実行するとこうなります。
ジェネレータで順番に出力されているのがわかります。
これをジェネレータ内包表記として書き換えるとこうなります。
gundam_list = ["EXIA","DYNAMES","KYRIOS","VIRTUE"]
g = (i for i in gundam_list)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
これまでと同様のやり方で書けますね。違いは丸括弧()で囲んでいるところです。あとはジェネレータの操作と一緒です。
実行してみましょう。
同じ結果が得られています。今回はnext()で1つずつ表示しましたが、for文を使って一気に表示してももちろん構いません。
また、これまでと同じように、後ろにif文をつけて条件を加えていくこともできます。
注意して欲しいのは、丸括弧()でくくっているので、タプルになるのでは無いかと間違わないようにすることです。
タプルにするにはtuple()を使って次のように書くことができます。
gundam_list = ["EXIA","DYNAMES","KYRIOS","VIRTUE"]
g = tuple(i for i in gundam_list)
print(g)
実行するとタプル型で出力されます。
もし、操作してる時にオブジェクトの型がわから無い場合はtype()に入れて確認してみましょう。
まとめ
Pythonには内包表記という書き方があります。これができると、Pythonの初心者ではない印象があります。
内包表記には、リスト内包表記、辞書内包表記、集合内包表記、ジェネレータ内包表記があります。
どれも書き方はリスト内包表記と同様な書き方で、括弧の種類などに気をつければ理解できると思います。
内包表記を使うと数行にわたるコードを1行で書くことができるので便利ですが、ループ処理をネストで繰り返すものを重ねすぎると逆にコードが見にくくなるので1つか2つのネストにするのが適当です。