Pythonはイテレータの振る舞いとnext(iterator)をリストします


147

考慮してください:

>>> lst = iter([1,2,3])
>>> next(lst)
1
>>> next(lst)
2

したがって、イテレータの前進は、予想通り、同じオブジェクトを変更することによって処理されます。

これが事実であると私は期待します:

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

毎秒の要素をスキップするにnextは:への呼び出しでイテレータを1回進める必要があります。次に、ループによって行われる暗黙の呼び出しでもう一度繰り返す必要があり、この2番目の呼び出しの結果がに割り当てられiます。

そうではありません。ループは、リスト内のすべての項目をスキップせずに印刷ます。

私が最初に思ったのは、ループiterは渡されたものを呼び出すために発生する可能性があり、独立したイテレータを提供する可能性があるということでした。これはそうではありませんiter(a) is a

では、なぜnextこの場合に反復子を進めないように見えるのでしょうか?

回答:


197

表示されているのは、反復ごとに出力されることに加えて、の戻り値をエコーバックするインタプリタです。next()i

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0
1
2
3
4
5
6
7
8
9

それほど0の出力であるprint(i)1からの戻り値next()等インタラクティブインタプリタによりエコーは、わずか5回の反復、端末に書き込まれる2行で得各反復があります。

next()物事の出力を割り当てると、期待どおりに機能します。

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    _ = next(a)
... 
0
2
4
6
8

または、インタラクティブなインタプリタエコーからの出力を区別するために追加情報をprint()出力します。

>>> a = iter(list(range(10)))
>>> for i in a:
...    print('Printing: {}'.format(i))
...    next(a)
... 
Printing: 0
1
Printing: 2
3
Printing: 4
5
Printing: 6
7
Printing: 8
9

つまり、next()は期待どおりに機能しますが、インタラクティブインタープリタによってエコーされたイテレータから次の値を返すため、ループには何らかの形で独自のイテレータコピーがあると考えられます。


13
私は通訳からのこの行動に気づいていませんでした。多くの時間を失う前に、いくつかの実際の問題を解決している間、それについて疑問に思っていたことがわかりました。
brandizzi 2013年

5
... *死にます*。最悪なのは、おそらくこのインタプリタの振る舞いをおそらく1週間前に誰かに言及したことを覚えていることです。
lvc 2013年

面白い。私はaでiを試しました:next(a); iを印刷し、1にジャンプして1,3,5,7,9を印刷すると思いました。しかし、それでも0、2、4、6、8です。どうして?
user2290820 2013

3
iすでに割り当てられていました。next(a)次の反復があることを意味2するために割り当てられi、その後、あなたが移動しa、再び、プリントに沿ってiなど、
マルタインピーテルス

1
nが奇数の場合、これは機能しません- リストがStopIteration出さnext(a)れた後にが呼び出されたときに例外が発生します。
Raf

13

何が起こっているかとnext(a)いうと、aの次の値が返されます。これは影響を受けないため、コンソールに出力されます。

あなたができることは、この値を持つ変数に影響を与えることです:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    b=next(a)
...
0
2
4
6
8

8

:彼らは間接的にしかコード例では不可欠な神秘の事を示しているので、私は、少し混乱既存の答えを見つけるの両方が *と「()次の」その結果を印刷する原因となっている「私は印刷します」。

元のシーケンスの交互の要素を出力していて、「next(a)」ステートメントが出力されているのは予期しないため、「print i」ステートメントがすべての値を出力しているように見えます。

その観点から、 "next(a)"の結果を変数に割り当てると、その結果の出力が禁止され、 "i"ループ変数の代替値のみが出力されることが明らかになります。同様に、「print」ステートメントを作成すると、より明確な何かが出力され、それも明確になります。

(既存の回答の1つは他の回答を否定します。その回答はサンプルコードがブロックとして評価されているため、インタープリターが「next(a)」の中間値を報告しないためです。)

質問に答える際の厄介なことは、一般に、答えを知った後、何が明白かを明確にすることです。それはとらえどころのないことができます。同様に、理解が深まったら答えを批評します。それは面白い...


2

Python /コンピューターに問題があります。

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

>>> 
0
2
4
6
8

期待どおりに動作します。

Python 2.7およびPython 3+でテストされています。両方で正しく動作します


5
@lvcと同じ結果が得られます(IDLEでのみですが、スクリプトとして実行すると、これが得られます)
jamylak 2013年

3
@Inbar Roseスクリプトとして実行する場合のみ。
Quintec 2014

1
対話型シェルを介してコードを配置する動作です。関数が使用されずに値を返す場合、インタプリタはそれをデバッグ出力としてシェルに出力します
Reishin

2

それでもわからない方へ。

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0 # print(i) printed this
1 # next(a) printed this
2 # print(i) printed this
3 # next(a) printed this
4 # print(i) printed this
5 # next(a) printed this
6 # print(i) printed this
7 # next(a) printed this
8 # print(i) printed this
9 # next(a) printed this

他の人がすでに言ったように、next期待どおりにイテレータを1増やします。戻り値を変数に割り当てても、魔法のように動作が変わるわけではありません。


1

関数として呼び出された場合、それはあなたが望むように動作します:

>>> def test():
...     a = iter(list(range(10)))
...     for i in a:
...         print(i)
...         next(a)
... 
>>> test()
0
2
4
6
8
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.