2016-11-02 4 views
4

次の2つのコードスニペットを考えてみましょう。Python 3の "list"呼び出しに奇妙な副作用があります

スニペット1

l = range(10) 
list(l) 
m = reversed(l) 
list(m) 
l = range(-1) 
list(l) 
list(m) 

スニペット2

l = range(10) 
m = reversed(l) 
l = range(-1) 
list(l) 
list(m) 

それらの間の唯一の違いは、スニペット2は、その前半にlist(l)list(m)を呼び出さないということです。

Bizzarely、スニペットでlist(m)への最終呼び出し1つの戻りこれらは異なる値であるスニペットにlist(m)への最終呼び出し2つの戻り

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 

一方

[] 

これは予想した動作ではありません。おそらく、スニペット1でのlist(l)list(m)への以前の呼び出しは、ある種のメモリ最適化を引き起こしています。誰が私に何が起こっているのか正確に説明することができますか?

>>> l = range(10) 
>>> list(l) 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>> m = reversed(l) 
>>> list(m) 
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 
>>> l = range(-1) 
>>> list(l) 
[] 
>>> list(m) 
[] 
>>> 
>>> l = range(10) 
>>> m = reversed(l) 
>>> l = range(-1) 
>>> list(l) 
[] 
>>> list(m) 
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 

ありがとうございます。

+2

反復子は、 'reversed'の戻り値と同様、使い捨てです。それらを2回反復する場合は、2つのイテレータを取得する必要があります。 – user2357112

+0

ああ、そうです。ありがとうございました。 – Jim

答えて

4

reversedは使い捨てであるイテレータを返す:あなたは(逆転項目からリストを作成します)listに初めてそれを養う後にそれが排出されます。あなたがlistを呼び出していない、あなたの第二のスニペットで

m = reversed(l) 
print(m) # <list_reverseiterator at 0x7fd2b8518fd0> 
list(m) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 
list(m) # [] (exhausted) 

その結果としての実行では、それは、イテレータが供給、mので、空のリストを得排出されると、それ以上の値が得られないことができますmにあるように、それを使い果たしてはいけません。

最後に一度だけ呼び出して、最後に表示されるリストを取得しています。

+0

Nitpick:1つのトリックポニーは1つのことしかできません。それを一回使用と呼ぶ方がいいです。 –

+0

@ThijsvanDien良い点、それを固定しました、ありがとう! –

関連する問題