itertools中的izip_longest:这里发生了什么?

Lau*_*low 7 python python-itertools

我很想知道下面的代码是如何工作的.它来自http://docs.python.org/library/itertools.html#itertools.izip_longest,并且是izip_longest迭代器的纯python等价物.我对哨兵功能特别神秘,它是如何工作的?

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
Run Code Online (Sandbox Code Playgroud)

Bjö*_*lex 6

好的,我们可以做到这一点.关于哨兵.该表达式([fillvalue]*(len(args)-1))创建一个列表,其中包含每个可迭代的一个填充值args,减去一个.所以,对于上面的例子['-'].counter然后分配该pop列表的-function.sentinel本身是一个生成器,在每次迭代时从该列表中弹出一个项目.您可以迭代sentinel一次返回的每个迭代器,它将始终产生fillvalue.返回的所有迭代器产生的项目总数sentinellen(args) - 1(感谢Sven Marnach澄清,我误解了它).

现在看看这个:

iters = [chain(it, sentinel(), fillers) for it in args]
Run Code Online (Sandbox Code Playgroud)

这就是诀窍.iters是一个列表,其中包含每个可迭代的迭代器args.这些迭代器中的每一个都执行以下操作:

  1. 迭代相应迭代中的所有项目args.
  2. 迭代过一次哨兵,屈服fillvalue.
  3. fillvalue永恒重复.

现在,正如之前所建立的那样,我们只能len(args)-1在它抛出之前一起迭代所有的哨兵IndexError.这很好,因为其中一个迭代是最长的.所以,当我们提到它IndexError被提升时,这意味着我们已经完成了对最长迭代的迭代args.

别客气.

PS:我希望这是可以理解的.

  • 另外,`sentinel()`可以无限次调用,不会引发任何异常. (2认同)

Sve*_*ach 5

该函数sentinel()返回仅产生fillvalue一次的迭代器.fillvalue返回的所有迭代器产生的s 总数sentinel()限制为n-1,n传递给它的迭代器数量izip_longest().在这个数量的fillvalues已经用尽之后,对返回的迭代器的进一步迭代sentinel()将引发一个IndexError.

此函数用于检测是否所有迭代器都已耗尽:每个迭代器都chain()使用返回的迭代器进行编辑sentinel().如果所有迭代器都耗尽,则返回的迭代器sentinel()将会第二n次迭代,从而产生一个IndexError,izip_longest()依次触发结束.

到目前为止,我解释了什么sentinel(),而不是它是如何工作的.当izip_longest()被调用时,的定义sentinel()进行了评价.在评估定义时,还要sentinel()评估默认参数to ,每次调用一次izip_longest().代码相当于

fillvalue_list = [fillvalue] * (len(args)-1)
def sentinel():
    yield fillvalue_list.pop()
Run Code Online (Sandbox Code Playgroud)

将它存储在默认参数而不是封闭范围中的变量中只是一个优化,因为它包含.pop在默认参数中,因为每次迭代返回的迭代器都会迭代查找它sentinel().