将列表函数应用于itertools.groupby中的嵌套生成器

时间:2016-12-20 15:48:18

标签: python python-3.x iterator generator

list函数在应用于嵌套生成器时的行为如何?在下面的代码片段中,我发现行为相当令人费解:似乎list消耗了大多数嵌套生成器,而最后一个仍然保留了一个元素:

>>> from itertools import groupby
>>> xs = [1, 2, 2, 3, 3]
>>> for k, g in list(groupby(xs)):
...     print(k, list(g))
1 []
2 []
3 [3]

1 个答案:

答案 0 :(得分:6)

不,对list的调用不会消耗嵌套的迭代器/生成器。

此行为是itertools.groupby所特有的,并在文档中进行了描述:

  

返回的组本身就是共享底层的迭代器   可与groupby()迭代。因为源是共享的,所以   groupby()对象已提前,上一组不再可见

[强调我的]

如果您查看文档中提供的等效于itertools.groupby的Python源代码,这将更加明确:

class groupby(object):
    def __init__(self, iterable, key=None):
        if key is None:
            key = lambda x: x
        self.keyfunc = key

        self.it = iter(iterable) # shared iterator

        self.tgtkey = self.currkey = self.currvalue = object()

    def __iter__(self):
        return self

    def next(self):
        while self.currkey == self.tgtkey:
            self.currvalue = next(self.it)    # Exit on StopIteration
            self.currkey = self.keyfunc(self.currvalue)
        self.tgtkey = self.currkey
        return (self.currkey, self._grouper(self.tgtkey))

    def _grouper(self, tgtkey):
        while self.currkey == tgtkey:
            yield self.currvalue
            self.currvalue = next(self.it)    # Exit on StopIteration
            self.currkey = self.keyfunc(self.currvalue)

结果中显示的最后一个[3]self.currvalue(由_grouper产生的),该groupby已经从groupby对象的上一次调用分配到了bluemix iam org-rename <old_org_name> <new_org_name> bluemix iam org-delete <org_name>

为了保留每个组的结果,您应该将它们存储在一个列表中,并且不会同时消耗{{1}}个对象。