Python列表迭代器行为及next(iterator)

186

请考虑:

>>> 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,迭代器应该先前进一次,然后循环隐含的调用会再次前进一次 - 这第二次调用的结果将被分配给i

但实际上并没有这样。循环打印了列表中的所有项,而没有跳过任何项。

我的第一个想法是可能是因为循环在所传递的对象上调用iter,并且这可能会给出一个独立的迭代器 - 但这并不是情况,因为我们有iter(a) is a

那么,为什么在这种情况下next似乎没有推进迭代器呢?

6个回答

250

你看到的是解释器在每次迭代时打印i并回显next()函数的返回值:

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

所以print(i)的输出为0next()的返回值为1,交互解释器会显示这些信息。总共有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() 的工作正常,但由于它返回迭代器的下一个值,并由交互式解释器回显,所以你会认为循环某种方式拥有自己的迭代器副本。

19
我之前没有意识到翻译器有这种行为。很高兴在解决一些实际问题时发现了这一点,避免了花费大量时间疑惑不解。 - brandizzi
5
... *死了*。最糟糕的是,我记得大约一周前曾向某人提到过这个口译员的行为。 - lvc
有趣。我尝试了“for i in a: next(a); print i”,并认为它会跳到1并打印1、3、5、7、9。但仍然是0、2、4、6、8。为什么? - user2290820
3
我已经被分配了。next(a) 的意思是下一次迭代将 2 分配给 i,然后再移动 a,打印 i 等等。 - Martijn Pieters
1
如果n是奇数,则此方法无效 - 当列表耗尽后调用next(a)时会引发StopIteration异常。 - Raf
这是一个非常透彻的解释。 - msarafzadeh

17

正在发生的是next(a)返回a的下一个值,它被打印到控制台因为它没有受到影响。

你可以做的是用这个值影响一个变量:

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

11

我认为现有的答案有点令人困惑,因为它们只间接地指示了代码示例中的基本神秘事物:同时*“print i ”和“next(a)”都导致它们的结果被打印。

由于它们交替打印原始序列的元素,并且出乎意料的是“next(a)”语句也在打印,因此似乎“print i ”语句正在打印所有值。

从这个角度来看,将“next(a)”的结果分配给变量会抑制其结果的打印,因此只打印“i”循环变量的交替值。同样,使“print”语句发出更加明显的信息可以消除歧义。

(其中一个现有的答案驳斥其他答案,因为该答案将示例代码评估为块,因此解释器不报告“next(a)”的中间值。)

总的来说,对问题进行回答的迷人之处在于当你知道答案时变得明显。 它可能会很难懂。同样,在理解答案后批评答案也很有趣。很有意思...


5

对于那些仍然不理解的人。

>>> 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。将其返回值分配给变量并不会神奇地改变其行为。


4

你的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
3
只有当你将其作为脚本运行时,它才会起作用。 - Quintec
3
这是通过交互式 shell 输入代码的行为。如果函数返回值没有被使用,解释器会将其作为调试输出打印到 shell 中。 - Reishin

1
当作函数调用时,它的行为符合您的期望:
>>> def test():
...     a = iter(list(range(10)))
...     for i in a:
...         print(i)
...         next(a)
... 
>>> test()
0
2
4
6
8

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接