Commits

INADA Naoki committed fe27e98

内包表記

Comments (0)

Files changed (1)

    4
    6
 
+
+内包表記
+---------
+
+リストを生成するコードを完結に書くための、リスト内包表記があります。
+例えば次のようなコードは::
+
+    >>> L = []
+    >>> for i in range(10):
+    ...     if i % 3 == 0:
+    ...         L.append(i+1)
+    ...
+    >>> L
+    [1, 4, 7]
+
+次のようにかけます。 ::
+
+    >>> L = [i+1 for i in range(10) if i%3 == 0]
+
+もとのコードと比べてみるとわかるように、
+
+1. 全体を [] で囲う
+2. 一番内側の ``.append(式)`` を、 [] の中の先頭に書く
+3. 続けて、 for と if をもとの順番で、 `:` は除いて書く
+
+という構造になっています。 if は、 for の後ろに1つしか書けないことに気をつけてください。
+上のルールに従えば、ネストしたループも内包表記でかけます。 ::
+
+    >>> [(x,y)
+    ...  for x in range(10) if x%2==0
+    ...  for y in range(20) if y%3==0]
+    [(0, 0), (0, 7), (0, 14), (3, 0), (3, 7), (3, 14), (6, 0), (6, 7), (6, 14), (9, 0), (9, 7), (9, 14)]
+
+ただし、ネストした内包表記は読みにくくなりやすいので、読みにくいと思ったら
+普通のループで書いてしまいましょう。
+
+リスト内包と似た、ジェネレータ内包表記もあります。
+例えば次のような、渡された iterable を1つずつ表示する関数があるとします。 ::
+
+    def print_all(iterable):
+        for it in iterable:
+            print(it)
+
+これを呼び出すとき、 ``print_all([i*2 for i in L])`` と書くと、一旦 L と同じ
+サイズのリストを作ってから関数を呼び出すので、 L と同じメモリを使ってしまいます。
+``print_all(i*2 for i in L)`` と書けば、リストではなくジェネレータで、
+要素を1つずつ渡すことができます。 (TODO: 別の場所でジェネレータを解説する)
+
+Python 2.7 と Python 3 では、リストとジェネレータ以外に、 dict と set も
+内包表記できます。
+どちらも Python 2.6 までは、コンストラクタにリスト内包やジェネレータ内包で
+書いた iterable を渡すことで実現していました。
+
+::
+
+    >>> {i:i*2 for i in range(10)}  # dict 内包
+    {0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}
+    >>> dict((i, i*2) for i in range(10))  # Python 2.6 までの書き方
+    {0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}
+
+    >>> {i*2 for i in range(10)}    # set 内包
+    set([0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
+    >>> set(i*2 for i in range(10)} # Python 2.6 までの書き方
+    set([0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
+