从这里: 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()
中改变它的行为呢?
答案 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
个对象......