我在https://more-itertools.readthedocs.io/en/latest/api.html中看到了循环法的代码段,但我无法理解最后一行nexts = cycle(islice(nexts, pending))
如何从nexts迭代器中删除耗尽的生成器。根据我的理解,这将从输入中删除最后一个,但是我们不应该删除第一个,即当前抛出此异常的那个?
def roundrobin(*iterables):
"""Yields an item from each iterable, alternating between them.
>>> list(roundrobin('ABC', 'D', 'EF'))
['A', 'D', 'E', 'B', 'F', 'C']
This function produces the same output as :func:`interleave_longest`, but
may perform better for some inputs (in particular when the number of
iterables is small).
"""
# Recipe credited to George Sakkis
pending = len(iterables)
if PY2:
nexts = cycle(iter(it).next for it in iterables)
else:
nexts = cycle(iter(it).__next__ for it in iterables)
while pending:
try:
for next in nexts:
yield next()
except StopIteration:
pending -= 1
nexts = cycle(islice(nexts, pending))
答案 0 :(得分:1)
我会一步一步地为你分手:
>>> list(roundrobin('ABC', 'D', 'EF'))
pending = 3 # len(('ABC', 'D', 'EF'))
# nexts roughly equivalent to:
['ABC', 'D', 'EF', 'ABC', 'D', 'EF', 'ABC', ...]
***
# the following get yielded
'A' from 'ABC' # nexts: ['D' , 'EF', 'BC', 'D' , 'EF', ...]
'D' from 'D' # nexts: ['EF', 'BC', '' , 'EF', 'BC', ...]
'E' from 'EF' # nexts: ['BC', '' , 'F' , 'BC', '' , ...]
'B' from 'BC' # nexts: ['' , 'F' , 'C' , '' , 'F' , ...]
# StopIteration was raised by what used to be "B"
SI from '' # nexts: ['F', 'C', '', 'F', 'C', '', 'F', ...]
# ^ index 2 (`pending`[see the following line])
# pending -= 1
pending = 2
# when islice() is used with one argument, it defaults to the "stop" index
# so islice() returns ['F', 'C']
# and cycle() converts it to ['F', 'C', 'F', 'C', ...]
pending = 2
nexts: ['F', 'C', 'F', 'C', ...]
# Go back to *** and continue until pending = 0
这就是最后一行如何删除耗尽的迭代。
主要想法:
for next in nexts:
yield next()
即使引发了StopIteration
,也已经从nexts
使用了耗尽的可迭代。
因此,nexts
中的第一项仍然是耗尽的可迭代:
nexts = ['', 'F', 'C', '', 'F', 'C', '', 'F', ...]
nexts
的第一项实际上是下一项:
nexts = ['F', 'C', '', 'F', 'C', '', 'F', ...]
答案 1 :(得分:1)
因为cycle()
创建了一个无限的迭代器,所以你并不总是从"开始"在最后一行中使用iterables
时islice()
的{{1}}。为了简化一点,最初定义的nexts
将"循环返回"到iterables
的开头:
try:
for next in nexts:
print(next())
except StopIteration:
print('decrementing...')
A
D
E
B
decrementing...
此时的目标是删除由'D'
形成的耗尽的迭代器。关键是你现在" at" 'EF'
,其中'ABC'
形成的迭代器位于下一行,因此islice(nexts, pending)
将从'EF'
循环到'ABC'
。
以下是相关示例:
x = cycle('abcd')
# ^ |
# |__|
for _ in range(3):
x.__next__()
list(islice(x, 2))
# ['d', 'a']