Pythonのzip関数の挙動

python


はてなブログ時代にPythonのzipの挙動についてちょろっと書いていたんですが、 やたら長ったるかったのでそれの再編的な。

要点

zip(*iterables)は、ドキュメント の等価コードにあるように、先に渡したイテラブルから処理していき、 いずれかのイテラブルがStopIterationを吐くまで続けます。

StopIterationを吐かせるイテラブルの位置に気をつけましょう。

渡す順番で挙動が変わる例

まず[0..8]のイテレータを作り、range(7)を先に渡してみます。

>>> a = iter(range(9))
>>> for i, j in zip(range(7), a):
...   print(i, j)
...
0 0
1 1
2 2
3 3
4 4
5 5
6 6

イテレータaの残りの中身は以下のようになっています。

>>> list(a)
[7, 8]

次に、先にaを渡してzipで回してみます。

>>> a = iter(range(9))
>>> for i, j in zip(a, range(7)):
...   print(i, j)
...
0 0
1 1
2 2
3 3
4 4
5 5
6 6

すると、aの中身は以下になっています。

>>> list(a)
[8]

これは、zip関数内部で先にaのnextを取って値7を得てから、 次にrange(7)のイテレーションを進めたらStopIterationを吐いたためzip関数のイテレーションが終了し、 値7は取り出されはするものの返されず、破棄されることに原因があります。

どのイテラブルにStopIterationを吐かせるかを考えてうまくzipを使ってあげたら 結構コードがイケてる感じになると思います。

あと最近は転置行列作る時にzip(*matrix)してる。

おまけ

ミュータブルとイテラブルは日本語にしづらくてちょっとアスペっぽくなるんですけどなんか解決策ありませんかね。