Python izip#u在itertools中最长:什么';这是怎么回事?
我很难理解下面的代码是如何工作的。它来自,是纯python的izip_最长迭代器的等价物。我对sentinel功能特别困惑,它是如何工作的Python izip#u在itertools中最长:什么';这是怎么回事?,python,itertools,Python,Itertools,我很难理解下面的代码是如何工作的。它来自,是纯python的izip_最长迭代器的等价物。我对sentinel功能特别困惑,它是如何工作的 def izip_longest(*args, **kwds): # izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- fillvalue = kwds.get('fillvalue') def sentinel(counter = ([fillvalue]*(l
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
中每个iterable的一个填充值减去一。因此,对于上面的示例['-']
<代码>计数器随后被分配该列表的-功能sentinel
本身是一个在每次迭代时从该列表中弹出一个项目的列表。您可以在sentinel
返回的每个迭代器上迭代一次,它将始终生成fillvalue
。sentinel
返回的所有迭代器生成的项目总数是len(args)-1
(感谢Sven Marnach澄清了这一点,我误解了它)
现在看看这个:
iters = [chain(it, sentinel(), fillers) for it in args]
这就是诀窍iters
是一个列表,其中包含args
中每个iterable的迭代器。每个迭代器都执行以下操作:
args
迭代相应iterable中的所有项fillvalue
fillvalue
len(args)-1次,然后它抛出索引器。这很好,因为其中一个是最长的。因此,当我们提到索引器
时,这意味着我们已经完成了对args
中最长的iterable的迭代
不客气
附言:我希望这是可以理解的。哨兵的定义几乎等同于
def sentinel():
yield ([fillvalue] * (len(args) - 1)).pop()
fillvalue_list = [fillvalue] * (len(args)-1)
def sentinel():
yield fillvalue_list.pop()
除了它将pop
绑定方法(函数对象)作为默认参数之外。默认参数在函数定义时计算,因此每次调用izip_longest
一次,而不是每次调用sentinel
一次。因此,函数对象“记住”列表[fillvalue]*(len(args)-1)
,而不是在每次调用中重新构造该列表。函数sentinel()
只返回一次生成fillvalue
的迭代器。sentinel()
返回的所有迭代器生成的fillvalue
s总数限制为n-1
,其中n
是传递给izip_longest()
的迭代器数。在用完此数量的fillvalue
s后,对sentinel()
返回的迭代器进行进一步迭代将产生索引器
此函数用于检测是否已耗尽所有迭代器:每个迭代器都使用sentinel()
返回的迭代器进行chain()
ed。如果所有迭代器都已用尽,则sentinel()
返回的迭代器将被第次迭代n
,从而生成索引器
,依次触发izip_longest()
的结束
到目前为止,我解释了sentinel()
的功能,而不是它的工作原理。调用izip_longest()
时,将计算sentinel()
的定义。在计算定义时,还会计算sentinel()
的默认参数,每次调用izip\u longest()
一次。代码相当于
def sentinel():
yield ([fillvalue] * (len(args) - 1)).pop()
fillvalue_list = [fillvalue] * (len(args)-1)
def sentinel():
yield fillvalue_list.pop()
将其存储在默认参数而不是封闭范围内的变量中只是一种优化,在默认参数中包含.pop
,因为每次迭代sentinel()
返回的迭代器时都可以省去查找。此外,sentinel()
可以无限次调用,不会引发任何异常。