从itertools.cycle中提取列表

pel*_*son 5 python python-itertools python-2.7

我有一个类,其中包含一个itertools.cycle我希望能够复制的实例.一种方法(我能想出的唯一方法)是提取初始可迭代(这是一个列表),并存储循环所处的位置.

不幸的是我无法掌握我用来创建循环实例的列表,似乎也没有明显的方法来做到这一点:

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']
Run Code Online (Sandbox Code Playgroud)

我可以提出一些合理的理由,为什么对某些类型的输入迭代不允许这样做,但是对于一个元组甚至一个列表(可变性可能是一个问题),我不明白为什么它不会是可能.

任何人都知道是否有可能从itertools.cycle实例中提取非无限可迭代.如果没有,任何人都知道为什么这个想法很糟糕?

Bak*_*riu 5

不可能。如果您查看itertools.cycle代码,您会发现它不存储序列的副本。它只创建一个迭代并将包含在迭代中的值存储在一个新创建的列表中:

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;
}
Run Code Online (Sandbox Code Playgroud)

这意味着在执行以下操作时:

itertools.cycle([1,2,3])
Run Code Online (Sandbox Code Playgroud)

您创建的列表只有 1 个引用,保存在循环使用的迭代器中。当迭代器耗尽时,迭代器被删除并创建一个新的迭代器:

    /* 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 */
Run Code Online (Sandbox Code Playgroud)

这意味着在执行一个循环后,列表将被销毁。

无论如何,如果您需要访问此列表,只需在调用itertools.cycle.