本連載も山場です。今回は内包表記についてお話します。内包表記は実際のPythonコードを読み書きする上で必須となりますので、複数のケースを見ながら丁寧に説明していこうと思います。
環境
- OS X 10.11.6
- Python 3.4.4
最終的なコード
リスト内包
内包表記にはリスト内包・ジェネレータ式・セット内包・辞書内包がありますが、本記事ではリスト内包についてご説明します。
まずはじめにリスト内包の説明を簡単にすると、ループ処理を使って複雑なリストを簡単に作る方法といえます。
はじめてのリスト内包
リスト内包の書き方
はじめにリスト内包のフォーマットを書いておきます。覚えておきましょう。
[式 for 変数 in イテレート可能オブジェクト]
カタチとしてはこのようになります。
これから実際にリスト内包を使っていきますが、
- 先に
forループ
の構成を考え 式
の部分で 添字を加工する
と2段階で考えると分かりやすいと思います。
最も簡単なリスト内包
[0, 1, 2, 3, 4]
上記リストを内包表記で書き直してみます。
[i for i in range(5)]
こんな感じになりました。
なんだか逆にややこしく感じますね。しかし慣れると非常にパワフルなのでぜひこの機会に学んで行きましょう。
後半for i in range(5)
の部分と前半i
の部分に分けて考えます。今回はrangeオブジェクト
から取り出された0〜4
までの数値が変数i
に入り、その要素i
がそのままリストのメンバーに入っています。
次の例と合わせると分かりやすいと思います。
rangeオブジェクト
の要素を二乗したメンバーを持つリスト
[0, 1, 4, 9, 16]
これはリスト内包でこのように書けます。
[i ** 2 for i in range(5)]
少しメリットが出てきました!for文
以下は変更ないので0〜4
までの数値がi
に入り、i ** 2
*1が新しく作られるリストのメンバーになるわけです。
添字を利用せず、単純なループとして扱う
今まで添え字を利用するケースを見てきましたが、全く同じ要素を10個持つリストなども簡単に作れます。
[13, 13, 13, 13, 13, 13, 13, 13, 13, 13]
こんなリストを作りたければ、下記のようにすればよいでしょう。
[13 for _ in range(10)]
添字は利用しないため_
とし、要素の部分には直値で13
を入れています。
ここでは例のため13
としましたが、勿論文字列だろうがなんだろうが大丈夫です。13
の替わりに'Hello'
を入れれば下記のようになるでしょう。
['Hello' for _ in range(10)]
もちろん出力結果は下記のとおりです。
['Hello', 'Hello', 'Hello', 'Hello', 'Hello', 'Hello', 'Hello', 'Hello', 'Hello', 'Hello']
イテレート可能オブジェクトに文字列を使用する
今まではイテレート可能オブジェクトにrangeオブジェクト
を指定してきましたが、実はPythonでは文字列もイテレート可能オブジェクトとして扱えます。
文字列を頭からひとつづつ取り出せるということです。便利ですね。やってみましょう!
['月', '火', '水', '木', '金', '土', '日']
上記リストを内包表記で作成しましょう。
[s for s in '月火水木金土日']
添字はi
からs
に変わりましたが同様に動作します。今回はstring
の頭文字であるs
とした訳です。
イテレート可能オブジェクトには'月下水木金土日'
を与えています。文字列が要素のリストは手で書くとシングル・ダブルクォーテーションとカンマが多く登場するので面倒ですが、内包表記だと楽ですね。
最後に応用として下記リストを作ってみましょう。答えを見ずにまずはトライしてみてください。
['月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日']
応用
答えは以下のとおりです。
['{}曜日'.format(s) for s in '月火水木金土日']
前回学んだformatメソッド
を利用しています。
このように内包表記を使えばかなり複雑なリストを作成することができます。今回は説明しませんが後置if
など使うとより自由な分岐も行えます。内包表記は実際のコードを読んでいても頻出するので、覚えておくと良いでしょう。
まとめ
リスト内包のみでひとつの記事になってしまいましたが、まだまだ内包表記の世界は奥深いので、研究してみると面白いかと思います。
*1:i*2だと2倍、i**2だと二乗になります