I have a class which contains a itertools.cycle
instance which I would like to be able to copy. One approach (the only one I can come up with), is to extract the initial iterable (which was a list), and store the position that the cycle is at.
Unfortunately I am unable to get hold of the list which I used to create the cycle instance, nor does there seem to be an obvious way to do it:
import itertools
c = itertools.cycle([1, 2, 3])
print dir(c)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__',
'__hash__', '__init__', '__iter__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', 'next']
I can come up with some half reasonable reasons why this would be disallowed for some types of input iterables, but for a tuple or perhaps even a list (mutability might be a problem there), I can't see why it wouldn't be possible.
Anyone know if its possible to extract the non-infinite iterable out of an itertools.cycle
instance. If not, anybody know why this idea is a bad one?
It's impossible. If you look at itertools.cycle
code you'll see that it does not store a copy of the sequence. It only create an iterable and store the values contained in the iterable in a newly created list:
static PyObject *
cycle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *it;
PyObject *iterable;
PyObject *saved;
cycleobject *lz;
if (type == &cycle_type && !_PyArg_NoKeywords("cycle()", kwds))
return NULL;
if (!PyArg_UnpackTuple(args, "cycle", 1, 1, &iterable))
return NULL;
/* NOTE: they do not store the *sequence*, only the iterator */
/* Get iterator. */
it = PyObject_GetIter(iterable);
if (it == NULL)
return NULL;
saved = PyList_New(0);
if (saved == NULL) {
Py_DECREF(it);
return NULL;
}
/* create cycleobject structure */
lz = (cycleobject *)type->tp_alloc(type, 0);
if (lz == NULL) {
Py_DECREF(it);
Py_DECREF(saved);
return NULL;
}
lz->it = it;
lz->saved = saved;
lz->firstpass = 0;
return (PyObject *)lz;
}
This means that when doing:
itertools.cycle([1,2,3])
The list you create has only 1 reference, that is kept in the iterator used by cycle. When the iterator is exhausted the iterator gets deleted and a new iterator is created:
/* taken from the "cycle.next" implementation */
it = PyObject_GetIter(lz->saved);
if (it == NULL)
return NULL;
tmp = lz->it;
lz->it = it;
lz->firstpass = 1;
Py_DECREF(tmp); /* destroys the old iterator */
Which means that after doing one cycle the list is destroyed.
Anyway if you need access to this list, just reference it somewhere before calling itertools.cycle
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With