@ゲー単走部

ローグライク雑記。変愚蛮怒、DCSSなど。

Python3で引っかかるところ~リストとイテレータ~

mapやzipがリストではなくイテレータを返すようになったので、挙動がややこしい。

>>>a = [10, 20, 30]
>>>b = [1, 2, 3]
>>>z = zip(a, b)
>>>list(z)
[(10, 1), (20, 2), (30, 3)]
>>>list(z)
[]
>>>list(z)
[]

zip(a, b)がリストではなくイテレータオブジェクトであり、それにlist関数を適用している。
1回listを適用した時点でイテレータが終了するので、2回目以降listを適用しても戻り値は空。

>>>a = [10, 20, 30]
>>>b = [1, 2, 3]
>>>list(zip(a, b))
[(10, 1), (20, 2), (30, 3)]
>>>list(zip(a, b))
[(10, 1), (20, 2), (30, 3)]
>>>list(zip(a, b))
[(10, 1), (20, 2), (30, 3)]

この場合、毎回新しいイテレータオブジェクトzip(a, b)を生成しているので、戻り値は期待通り。

>>>a = [10, 20, 30]
>>>b = [1, 2, 3]
>>>z = list(zip(a, b))
>>>z
[(10, 1), (20, 2), (30, 3)]
>>>z
[(10, 1), (20, 2), (30, 3)]
>>>z
[(10, 1), (20, 2), (30, 3)]

この場合、イテレータzip(a, b)をlistに変換したものを変数zに保存しているので、zの値は変わらず、出力は期待通り。

>>>a = range(5)
>>>list(a)
[0, 1, 2, 3, 4]
>>>list(a)
[0, 1, 2, 3, 4]
>>>list(a)
[0, 1, 2, 3, 4]

はぁ?
Python3だとrange関数はリストではなくイテレータを返すはずなので、2回目以降のlist(a)は空になるんじゃないの?
何で?


<追記>
公式リファレンスを見たが、rangeは組み込み関数ではなく組み込み型、クラスだった模様。
それにイテレータオブジェクトというわけではないようだ。と思うしかない。xrangeと統合されてメモリ使用効率がよくなっただけ。
と考えないと↓の挙動との違いが説明できないし。

>>>a = iter([1, 3, 5])
>>>list(a)
[1, 3, 5]
>>>list(a)
[]
>>>list(a)
[]