冗長読解シリーズ - ネストされた内包表記

大きな勘違いをしてたのでPythonチュートリアルのネストされた内包表記の例を冗長に読解しています。

元ネタはこれ。

matrix = [
    [1,2,3,4],
    [5,6,7,8],
    [9,10,11,12],
]

[[row[i] for row in matrix] for i in range(4)]

元ネタの結果

[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

で、最初に”こう動いてるはずなんだけど”と勘違いして冗長に書いてみたけど動かなかった私の理解がこう。

for row in matrix:
    print row
    for i in range(4):
        print row[i]

当然こう▼なります。

[1, 2, 3, 4]
1
2
3
4
[5, 6, 7, 8]
5
6
7
8
[9, 10, 11, 12]
9
10
11
12

▲の例で根本的な勘違いは、先にfor row in matrixを回してしまってることです。


ここで改めてリスト内包表記の基礎をおさらいすると、

l = [i for i in range(4)]

l = []
for i in range(4):
    l.append(i)

と等価です。


なので、まず

[[i] for i in range(4)]

とすると、

[[0], [1], [2], [3]]

が返ってきます。

これが分かると、
for i in range(4)がまず評価されて、iの値がfor row in matrixに渡って、さらにrow[i]の値がネストされたリストに追加されていることがわかるので、次のコードと等価だということがわかります。

dummy = []

dummy = []
for i in range(4):
    dummy_nested = []
    for row in matrix:
        dummy_nested.append(row[i])
    dummy.append(dummy_nested)


すっきり! \ ^ o ^/


追記:チュートリアルにも書いてあるように、実際はこう書きましょう

zip(*matrix)