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)
好的,我们可以做到这一点.关于哨兵.该表达式([fillvalue]*(len(args)-1))创建一个列表,其中包含每个可迭代的一个填充值args,减去一个.所以,对于上面的例子['-'].counter然后分配该pop列表的-function.sentinel本身是一个生成器,在每次迭代时从该列表中弹出一个项目.您可以迭代sentinel一次返回的每个迭代器,它将始终产生fillvalue.返回的所有迭代器产生的项目总数sentinel是len(args) - 1(感谢Sven Marnach澄清,我误解了它).
现在看看这个:
iters = [chain(it, sentinel(), fillers) for it in args]
Run Code Online (Sandbox Code Playgroud)
这就是诀窍.iters是一个列表,其中包含每个可迭代的迭代器args.这些迭代器中的每一个都执行以下操作:
args.fillvalue.fillvalue永恒重复.现在,正如之前所建立的那样,我们只能len(args)-1在它抛出之前一起迭代所有的哨兵IndexError.这很好,因为其中一个迭代是最长的.所以,当我们提到它IndexError被提升时,这意味着我们已经完成了对最长迭代的迭代args.
别客气.
PS:我希望这是可以理解的.
该函数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().