mapとzipのまとめ

2chPythonのお勉強 Part30の834によるとmapとimapによると微妙に挙動が異なるらしい。例えば以下を2.5.xでテスト。

>>> map(lambda *xs: xs, (0,1,2), (3,4,5), (6,7))
[(0, 3, 6), (1, 4, 7), (2, 5, None)]

>>> list(imap(lambda *xs: xs, (0,1,2), (3,4,5), (6,7)))
[(0, 3, 6), (1, 4, 7)]

mapでは長い方に合わせて、imapでは短い方に合わせるらしい。mapのシグネチャは以下。

map(function, sequence[, sequence, ...])


functionにNoneを使用すると値をそのまま返す。つまりfunctionに上記の lambda *xs: xs を与えたと同様な挙動となる。

>>> map(None, (0,1,2), (3,4,5), (6,7))
[(0, 3, 6), (1, 4, 7), (2, 5, None)]

>>> list(imap(None, (0,1,2), (3,4,5), (6,7)))
[(0, 3, 6), (1, 4, 7)]


次にzipの挙動。zipとizipは返すものがリストとイテレータという違いだけで、それ以外の挙動は同じ。

>>> zip((0,1,2), (3,4,5), (6,7))
[(0, 3, 6), (1, 4, 7)]

zipは短い方に合わせる。つまりimapと似た動作となる。zipのシグネチャは以下。

zip(seq1 [, seq2 [...]])


map系関数の注意点としては複数のsequenceの展開したものを関数の引数として渡す。1つのタプルが引数として渡される訳ではない。

>>> map(lambda a: a, (0,1,2))
[0, 1, 2]

>>> map(lambda a,b: (a,b), (0,1,2), (3,4))
[(0, 3), (1, 4), (2, None)]

>>> map(lambda a,b,c: (a,b,c), (0,1,2), (3,4,5), (6,7))
[(0, 3, 6), (1, 4, 7), (2, 5, None)]


可変長の引数を1つのタプルにまとめる場合は、引数にアスタリスクを付ける。

>>> map(lambda *xs: xs, (0,1,2))
[(0,), (1,), (2,)]

>>> map(lambda *xs: xs, (0,1,2), (3,4))
[(0, 3), (1, 4), (2, None)]

>>> map(lambda *xs: xs, (0,1,2), (3,4,5), (6,7))
[(0, 3, 6), (1, 4, 7), (2, 5, None)]

もしくは、以下のようにzipと組み合わせる。但し、zipは短い方に合わせるので、mapと組み合わせると挙動が異なる。imapと組み合わせると同じ挙動となる。各sequenceの長さが全て同じであればzipと組み合わせてもmapと同じ挙動となる。

>>> map(lambda *xs: xs, (0,1,2), (3,4))
[(0, 3), (1, 4), (2, None)]
>>> map(lambda xs: xs, zip((0,1,2), (3,4)))
[(0, 3), (1, 4)]

>>> list( imap(lambda *xs: xs, (0,1,2), (3,4)) )
[(0, 3), (1, 4)]
>>> list( imap(lambda xs: xs, zip((0,1,2), (3,4))) )
[(0, 3), (1, 4)]

次に2.6.xと3.0を考えてみる。3.0のmapは2.5.xのimapと同等な挙動となる。そのためporting(移植)する際にはmapとimapの挙動の違いを意識しないと互換性が崩れる場合がある。挙動をまとめると以下の通り。

2.5.x 2.6.x 3.0
map sequenceの長い方に合わせる 2.5.xのmapと同等 2.5.xや2.6.xのimapと同等
imap sequenceの短い方に合わせる 2.5.xのimapと同等 存在しない
zip sequenceの短い方に合わせる 2.5.xのzipと同等 2.5.xや2.6.xのizipと同等
izip sequenceの短い方に合わせる 2.5.xのizipと同等 存在しない
zip_longest 存在しない sequenceの長い方に合わせる 2.6.xのzip_longestと同等


但し、3.0のmap系関数では第一引数のfunctionにNoneを指定するとエラーになるので注意。