now becames exhausted after advancing the groupby iterator.
def __iter__(self):
return self
def __next__(self):
+ self.id = object()
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:
+ return (self.currkey, self._grouper(self.tgtkey, self.id))
+ def _grouper(self, tgtkey, id):
+ while self.id is id and self.currkey == tgtkey:
yield self.currvalue
try:
self.currvalue = next(self.it)
self.assertEqual(set(keys), expectedkeys)
self.assertEqual(len(keys), len(expectedkeys))
+ # Check case where inner iterator is used after advancing the groupby
+ # iterator
+ s = list(zip('AABBBAAAA', range(9)))
+ it = groupby(s, testR)
+ _, g1 = next(it)
+ _, g2 = next(it)
+ _, g3 = next(it)
+ self.assertEqual(list(g1), [])
+ self.assertEqual(list(g2), [])
+ self.assertEqual(next(g3), ('A', 5))
+ list(it) # exhaust the groupby iterator
+ self.assertEqual(list(g3), [])
+
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ it = groupby(s, testR)
+ _, g = next(it)
+ next(it)
+ next(it)
+ self.assertEqual(list(pickle.loads(pickle.dumps(g, proto))), [])
+
# Exercise pipes and filters style
s = 'abracadabra'
# sort s | uniq
--- /dev/null
+An iterator produced by itertools.groupby() iterator now becames exhausted
+after advancing the groupby iterator.
PyObject *tgtkey;
PyObject *currkey;
PyObject *currvalue;
+ const void *currgrouper; /* borrowed reference */
} groupbyobject;
static PyTypeObject groupby_type;
{
PyObject *newvalue, *newkey, *r, *grouper;
+ gbo->currgrouper = NULL;
/* skip to next iteration group */
for (;;) {
if (gbo->currkey == NULL)
Py_INCREF(parent);
igo->tgtkey = tgtkey;
Py_INCREF(tgtkey);
+ parent->currgrouper = igo; /* borrowed reference */
PyObject_GC_Track(igo);
return (PyObject *)igo;
PyObject *newvalue, *newkey, *r;
int rcmp;
+ if (gbo->currgrouper != igo)
+ return NULL;
if (gbo->currvalue == NULL) {
newvalue = PyIter_Next(gbo->it);
if (newvalue == NULL)
static PyObject *
_grouper_reduce(_grouperobject *lz)
{
+ if (((groupbyobject *)lz->parent)->currgrouper != lz) {
+ return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
+ }
return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->parent, lz->tgtkey);
}