itertools中的izip_longest:这是怎么回事? [英] izip_longest in itertools: what's going on here?
问题描述
我正在努力理解以下代码的工作方式.来自 http://docs.python.org/library/itertools.html#itertools .izip_longest ,与izip_longest迭代器的纯Python等效.我尤其对哨兵功能感到迷惑,它是如何工作的?
I'm struggeling to understand how the below code works. It's from http://docs.python.org/library/itertools.html#itertools.izip_longest, and is the pure-python equivalent of the izip_longest iterator. I'm especially mystified by the sentinel function, how does it work?
def izip_longest(*args, **kwds):
# izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
fillvalue = kwds.get('fillvalue')
def sentinel(counter = ([fillvalue]*(len(args)-1)).pop):
yield counter() # yields the fillvalue, or raises IndexError
fillers = repeat(fillvalue)
iters = [chain(it, sentinel(), fillers) for it in args]
try:
for tup in izip(*iters):
yield tup
except IndexError:
pass
推荐答案
好的,我们可以做到这一点.关于哨兵.表达式([fillvalue]*(len(args)-1))
创建一个列表,该列表包含args
中每个可迭代值的一个填充值减一个.因此,对于上面的示例['-']
.然后为counter
分配了该列表的 pop
-函数. sentinel
本身是生成器,它会在每个列表中弹出一个项目迭代.您可以仅对sentinel
返回的每个迭代器进行一次迭代,并且始终会生成fillvalue
. sentinel
返回的所有迭代器产生的项目总数为len(args) - 1
(感谢Sven Marnach澄清了这一点,我误解了).
Ok, we can do this. About the sentinel. The expression ([fillvalue]*(len(args)-1))
creates a list that contains one fill value for each iterable in args
, minus one. So, for the example above ['-']
. counter
is then assigned the pop
-function of that list. sentinel
itself is a generator that pops one item from that list on each iteration. You can iterate over each iterator returned by sentinel
exactly once, and it will always yield fillvalue
. The total number of items yielded by all iterators returned by sentinel
is len(args) - 1
(thanks to Sven Marnach for clarifying that, I misunderstood it).
现在检查一下:
iters = [chain(it, sentinel(), fillers) for it in args]
那是诀窍. iters
是一个列表,其中包含args
中每个可迭代对象的迭代器.这些迭代器均执行以下操作:
That is the trick. iters
is a list that contains an iterator for each iterable in args
. Each of these iterators does the following:
- 遍历
args
中对应的可迭代项中的所有项. - 遍历哨兵一次,产生
fillvalue
. - 对所有永恒重复
fillvalue
.
- Iterate over all items in the corresponding iterable from
args
. - Iterate over sentinel once, yielding
fillvalue
. - Repeat
fillvalue
for all eternity.
现在,如前所述,我们只能在抛出IndexError
之前,将所有哨兵一起迭代len(args)-1
次.很好,因为其中一个可迭代项最长.因此,当我们提到IndexError
升高时,这意味着我们已经完成了对args
中最长的迭代的迭代.
Now, as established earlier, we can only iterate over all sentinels together len(args)-1
times before it throws an IndexError
. This is fine, because one of the iterables is the longest. So, when we come to the point that the IndexError
is raised, that means we have finished iterating over the longest iterable in args
.
不客气.
P.S .:我希望这是可以理解的.
P.S.: I hope this is understandable.
这篇关于itertools中的izip_longest:这是怎么回事?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!