pythonitertools:与islice一起使用cycle

pythonitertools:与islice一起使用cycle,python,itertools,Python,Itertools,问题: 我有下面的代码。我想知道为什么我在下面的代码中是否包含带有注释的行并不重要 #!/usr/bin/env python from itertools import * import time cc = cycle([ iter([1,2,3]), iter([4]) , iter([5,6]) ] ) p = 3 while p: try: for k in cc: print k.next() except StopIterat

问题:

我有下面的代码。我想知道为什么我在下面的代码中是否包含带有注释的行并不重要

#!/usr/bin/env python

from itertools import *
import time
cc = cycle([ iter([1,2,3]), iter([4]) , iter([5,6]) ] )
p = 3
while p:
    try:
        for k in cc:
            print k.next()
    except StopIteration:
        p = p - 1
        cc = cycle(islice(cc,  p))  # this does not matter
输出:

1
4
5
2
6
3
同时在以下位置签出
roundrobin
recipe

此代码显示
islice
正在影响
cc

#!/usr/bin/env python

from itertools import *
import time
cc = cycle([ iter([1,2,3]), iter([4]) , iter([5,6]) ] )
p = 3
while p:
    try:
        for k in cc:
            print k,k.next()
    except StopIteration:
            print "stop iter"
            p = p - 1
            cc = cycle(islice(cc,  p)) 
输出

<listiterator object at 0x7f32bc50cfd0> 1
<listiterator object at 0x7f32bc518050> 4
<listiterator object at 0x7f32bc518090> 5
<listiterator object at 0x7f32bc50cfd0> 2
<listiterator object at 0x7f32bc518050> stop iter
<listiterator object at 0x7f32bc518090> 6
<listiterator object at 0x7f32bc50cfd0> 3
<listiterator object at 0x7f32bc518090> stop iter
<listiterator object at 0x7f32bc50cfd0> stop iter
1
4.
5.
2.
停止iter
6.
3.
停止iter
停止iter

嗯。。。看起来它在做我们期待的事情

所以,通常情况下,循环是这样工作的:

cycle([1,2,3,4,5]) -> [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
[iter(a), iter(b), iter(c), iter(a), iter(b), iter(c), iter(a), iter(b), iter(c), ...]
它将存储值,直到获得StopIterator,然后开始从保存的列表返回值。在本例中,这将是
[iter(a),iter(b),iter(c)]
(其中iter(x)是一个listiterator对象本身,跨越任何内部对象)。所以chain实际上返回的是这样的东西:

cycle([1,2,3,4,5]) -> [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
[iter(a), iter(b), iter(c), iter(a), iter(b), iter(c), iter(a), iter(b), iter(c), ...]
运行时的外观:

[1, 4, 5, 2, StopIterator]
但这是k.next()的值,不是k。cc本身没有返回StopIterator,它返回的对象是

现在,您可以调用
islice(cc,2)
。这应该返回序列
[iter(c),iter(a)]
,因为它们是序列中的下两个项目。同样,您希望cc循环它们,但现在您应该

[iter(c), iter(a), iter(c), iter(a), iter(c), iter(a), ...]
您不会注意到有多大的差异,但这是因为您的切片长度小于原始切片的长度。换言之,原作本应消失 [国际热核实验堆(c)、国际热核实验堆(a)、国际热核实验堆(b)、国际热核实验堆(c)、国际热核实验堆(a),…]

但是你必须走得比两个项目更远才能看到差异,而且

你开始脱下衣服,你就可以

[6, 3, StopIterator]
只有两个项目,所以他们是相同的两个项目,你会得到没有岛

现在,当您执行
islice(cc,2)
时,您将得到接下来的两个项目,即
[iter(a),iter(c)]
。这两个都已经精疲力竭了,所以你可以

[StopIterator]
还有你的确切顺序


我不知道您期望的是什么,但这完全符合我的期望。

短期课程:有无重新绑定
cc
的行为通常不相同,但对于您使用的特定输入,的输出恰好是相同的

长课程:让我们称你的三个迭代器为A、B和C

没有
cc
重新绑定:A产生1,B产生4,C产生5,A产生2,B产生
StopIteration
<代码>p下降到2。然后C生成6,A生成3,B再次生成
StopIteration
<代码>p降到1。C引发
StopIteration
p
降至0,循环退出

使用
cc
重新绑定:A生成1,B生成4,C生成5,A生成2,B引发
StopIteration
<代码>p下降到2。到目前为止一切都一样。循环算法中重新绑定的目的是删除耗尽的迭代器。碰巧在这个具体的例子中,它对结果没有影响。通过重新绑定
islice(cc,2)
cc
中获取“下两件事”,按顺序,C和A.B不再存在。然后将C和A放入一个新的
循环

然后C生成6,A生成3,C生成
StopIteration
<代码>p降到1。
cc
重新绑定去掉了C(耗尽的迭代器),在新的
循环中只留下A。循环循环循环,并引发
StopIteration
<代码>p
降到0,我们就完成了

当然,删除耗尽的迭代器对于使循环正常工作至关重要。但是,如您所示,在某些特定情况下,这并不重要:-)

简单例子 重新绑定
cc
会产生巨大差异的简单情况:

cc = cycle([iter([1,2,3,4,5]), iter([])])
p = 2

通过重新绑定,我们得到所有5个值。如果不重新绑定,我们只能得到1和2。

为什么你认为这很重要?在1,4,5,2
StopIteration
被引发之后,您告诉它从cc中获取下一个p=2项。但是只剩下2个项目,所以这与让它运行到底是一样的(即,与不重置
cc
)相同。@TimPeters这不对,只有两个迭代器不保留,所有三个迭代器都保留。其中一个是空的。没有说迭代器,说项目:只剩下6和3
islice
在生成的项目序列上工作,而不是在被切片的迭代器的内部结构上。顺便说一句,
roundrobin
配方也可以很好地工作,如果您注释掉其中的相应行-试试看!这里有一个例子,它确实起到了作用:改变到
循环([iter([1,2,3])、iter([4])、iter([5,6])、iter([7,8,9,10]))
这比我最初想的要复杂;-)