itertools“石斑鱼”功能配方如何工作?

时间:2018-03-08 19:18:29

标签: python

从这里: https://docs.python.org/3/library/itertools.html#itertools-recipes

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

我理解zip_longest电话。但我没有得到:

args = [iter(iterable)] * n

如果你以后要将一个iterable传递给izip_longest,为什么还要麻烦地将iterable包装成iter()?我不能这样做:

args = [iterable] * n

但似乎没有iter(),它只重复相同的迭代器n次。但是如何在iter()中改变它的行为呢?

1 个答案:

答案 0 :(得分:3)

这个分组利用了迭代器的单遍特性(与仅仅可迭代相反,可以多次迭代,并且在非迭代器上使用iter可迭代应该返回一个新的,相反,在迭代器上调用iter会返回迭代器本身

所以这里是一个简单的zip函数实现,只有两个参数:

In [1]: def myzip(x, y):
   ...:     itx, ity = iter(x), iter(y)
   ...:     while True:
   ...:         try:
   ...:             a, b = next(itx), next(ity)
   ...:         except StopIteration:
   ...:             return
   ...:         yield a, b
   ...:

In [2]: list(zip('abcd','efgh'))
Out[2]: [('a', 'e'), ('b', 'f'), ('c', 'g'), ('d', 'h')]

In [3]: list(myzip('abcd','efgh'))
Out[3]: [('a', 'e'), ('b', 'f'), ('c', 'g'), ('d', 'h')]

这几乎就是内置zip的工作原理。现在,如果我们使用列表作为可迭代来完成上述操作呢?

In [16]: mylist = [1,2,3,4]

In [17]: iterable = mylist

In [18]: itx, ity = iter(iterable), iter(iterable)

In [19]: itx is ity
Out[19]: False

In [20]: next(itx), next(ity)
Out[20]: (1, 1)

In [21]: next(itx), next(ity)
Out[21]: (2, 2)

In [22]: next(itx), next(ity)
Out[22]: (3, 3)

In [23]: next(itx), next(ity)
Out[23]: (4, 4)

In [24]: next(itx), next(ity)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-24-b6cbb26d280f> in <module>()
----> 1 next(itx), next(ity)

StopIteration:

但是,如果iterable迭代器

In [25]: iterable = iter(mylist)

In [26]: itx, ity = iter(iterable), iter(iterable)

In [27]: itx is ity
Out[27]: True

In [28]: next(itx), next(ity)
Out[28]: (1, 2)

In [29]: next(itx), next(ity)
Out[29]: (3, 4)

In [30]: next(itx), next(ity)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-30-b6cbb26d280f> in <module>()
----> 1 next(itx), next(ity)

StopIteration:

最后,请注意,对序列的重复永远不会复制序列的元素,因此执行[iter(x)]*n会返回一个列表,其中包含对同一迭代器的n个引用,因此:

In [32]: args = [iter(mylist)]*3

In [33]: args
Out[33]:
[<list_iterator at 0x1040c9320>,
 <list_iterator at 0x1040c9320>,
 <list_iterator at 0x1040c9320>]

注意,它们是相同的list_iterator个对象......