ジェネレーター式と内包表記を使ってみよう:特集:Visual Studioで始めるPythonプログラミング(2/2 ページ)
今回はジェネレーター式とリストなどの内包表記を取り上げる。これらはラムダ式と並んでPython的なコードを書くのによく使われる要素だ。
少し高度な内包表記の例
前ページで見た内包表記は非常にシンプルなものだったが、二重のforループに相当する処理を内包表記で表現したり、「式」を適用する前に要素のフィルタリングを行ったりすることもできる。以下では、少し高度な内包表記の使い方を見てみよう。
for節のネスト
まずは以下のforループを見てみよう。
>>> l = []
>>> for x in range(3):
... for y in range(4):
... l.append((x, y))
...
>>> l
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), …… 省略 ……, (2, 2), (2, 3)]
このコードではfor文を二重にループさせて、(0, 0)〜(2, 3)のタプルをリストに追加している。これと同等な処理を内包表記で記述すると次のようになる。
>>> l = [(x, y) for x in range(3) for y in range(4)]
>>> l
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), …… 省略 ……, (2, 2), (2, 3)]
このように「for節」(for ターゲットリスト in 反復可能オブジェクト)をネストさせることで、二重ループをするよりも簡潔な形でコードを記述できる。for文を使った場合とループと同じ順序でfor節をネストさせればよいので、forループのネストからfor節のネストへの頭の切り替えはそれほど難しくはないだろう。このことが手や体や頭に染みついてきたら、次の内包表記の意味も分かるようになる。
>>> [num for item in [[1], [2, 3], [4, 5, 6]] for num in item]
[1, 2, 3, 4, 5, 6]
ネストしたfor節はネストしたfor文と同じ順序で書かれるので、これはおおよそ次のようなforループと同等だと考えればよい。
for item in [[1], [2, 3], [4, 5, 6]]:
for num in item:
# numをリストの要素に追加
一見すると難解な表現でも、最初のうちは自分が理解できている構文要素へ展開してみると「ああ、そういうことか」となるので、つまずいたときには基本に戻ってみるようにしよう。
if節による要素のフィルタリング
for節に続けて「if節」を記述すると、元の反復可能オブジェクトから要素をフィルタリングできる。以下に例を示す。
>>> l = ["Windows Server Insider", "Insider.NET", "Server & Storage", "HTML5 + UX"]
>>> l2 = [item for item in l if "Insider" in item] # "Insider"が含まれる要素からなるリストを作成
>>> l2
['Windows Server Insider', 'Insider.NET']
>>> s = {x * x for x in range(10) if x % 2 == 0} # 偶数のみを取り出し、その二乗からなる集合を作成
>>> s
{0, 16, 64, 4, 36}
>>> s = {x * x for x in range(10) if x % 2} # 奇数のみを取り出し、その二乗からなる集合を作成
>>> s
{81, 1, 49, 9, 25}
for節がネストしている場合、if節はそれぞれに付加できる。以下はrange(5)の範囲でxには奇数のみ、yには偶数のみを取り出して、それらを組み合わせたタプルを要素とするリストを作成している。
>>> [(x, y) for x in range(5) if x % 2 for y in range(5) if not y % 2]
[(1, 0), (1, 2), (1, 4), (3, 0), (3, 2), (3, 4)]
なお、Pythonでは三項演算子(条件演算子)の代わりに条件式が使える。以下に構文を示す。
式1 if 条件 else 式2
この式ではまず「条件」が評価される。その値が真であれば「式1」の値が、偽であれば「式2」の値がその式の評価結果となる。そのため、else以降を省略することはできない。
使用例を以下に示す。以下は乱数が偶数か奇数かでその値が変化する条件式だ。
>>> import random
>>> 100 if random.randint(0,10) % 2 else 200
100
>>> 100 if random.randint(0,10) % 2 else 200
200
この条件式を「式」部分に記述することも可能だ。for節に続けるif節とは異なるので注意が必要だ。強調表示した部分が内包表記の「式」に当たる。
>>> l = ["Windows Server Insider", "Insider.NET", "Server & Storage", "HTML5 + UX"]
>>> [item if "Insider" in item else "outsider" for item in l]
['Windows Server Insider', 'Insider.NET', 'outsider', 'outsider']
zip関数との組み合わせ
最後にzip関数を使った辞書の作成を見てみる。zip関数は複数の反復可能オブジェクトを受け取り、それらの要素を一組にしたタプル(のイテレータ)を返送する。これを利用すると、例えば、以下のような辞書を作成できる。
>>> l = ["Windows Server Insider", "Insider.NET", "Server & Storage", "HTML5 + UX"]
>>> {"forum {0}".format(n) : forum for n, forum in zip(range(1,5), l)}
{'forum 2': 'Insider.NET', 'forum 4': 'HTML5 + UX', 'forum 3': 'Server & Storage', 'forum 1': 'Windows Server Insider'}
今回は前回積み残したジェネレーター式と、それとよく似た構文を持つリスト/集合/辞書の内包表記について見てきた。次回はモジュールとクラスなどを取り上げる予定だ。
Copyright© Digital Advantage Corp. All Rights Reserved.