Python 从itertools.cycle中提取列表

Python 从itertools.cycle中提取列表,python,python-2.7,itertools,Python,Python 2.7,Itertools,我有一个类,它包含一个itertools.cycle实例,我希望能够复制它。一种方法(我唯一能想到的方法)是提取初始iterable(它是一个列表),并存储循环所在的位置 不幸的是,我无法获得用于创建cycle实例的列表,似乎也没有明显的方法: import itertools c = itertools.cycle([1, 2, 3]) print dir(c) ['__class__', '__delattr__', '__doc__', '__format__', '__getattrib

我有一个类,它包含一个
itertools.cycle
实例,我希望能够复制它。一种方法(我唯一能想到的方法)是提取初始iterable(它是一个列表),并存储循环所在的位置

不幸的是,我无法获得用于创建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']
我可以提出一些不太合理的理由来解释为什么某些类型的输入iterables不允许这样做,但是对于元组或者甚至是列表(可变性可能是一个问题),我不明白为什么不允许这样做


任何人都知道,如果可以从
itertools.cycle
实例中提取非无限iterable。如果没有,有人知道为什么这个主意不好吗?

这是不可能的。如果查看
itertools.cycle
code,您将看到它没有存储序列的副本。它仅创建iterable并将iterable中包含的值存储在新创建的列表中:

静态PyObject*
cycle_new(PyTypeObject*类型、PyObject*参数、PyObject*kwds)
{
PyObject*it;
PyObject*iterable;
PyObject*已保存;
循环对象*lz;
if(type==&cycle\u type&&!\u PyArg\u NoKeywords(“cycle()”,kwds))
返回NULL;
if(!PyArg_unpactuple(args,“cycle”、1、1和iterable))
返回NULL;
/*注意:它们不存储*序列*,只存储迭代器*/
/*获取迭代器*/
it=PyObject_GetIter(iterable);
if(it==NULL)
返回NULL;
保存=PyList_New(0);
如果(已保存==NULL){
Py_DECREF(it);
返回NULL;
}
/*创建cycleobject结构*/
lz=(cycleobject*)类型->tp_alloc(类型,0);
if(lz==NULL){
Py_DECREF(it);
Py_DECREF(已保存);
返回NULL;
}
lz->it=it;
lz->保存=保存;
lz->firstpass=0;
返回(PyObject*)lz;
}
这意味着在执行以下操作时:

itertools.循环([1,2,3])
您创建的列表只有一个引用,它保存在cycle使用的迭代器中。 当迭代器耗尽时,迭代器将被删除并创建一个新的迭代器:

/*取自“cycle.next”实现*/
它=PyObject_GetIter(lz->保存);
if(it==NULL)
返回NULL;
tmp=lz->it;
lz->it=it;
lz->firstpass=1;
Py_DECREF(tmp);/*破坏旧的迭代器*/
这意味着在完成一个循环后,列表将被销毁


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

之前在某个地方引用它。如果您有办法知道
cycle
生成的对象的某些属性,那么您可以推导出内部列表。例如,如果您知道循环中的所有对象都是不同的,并且除了您之外没有其他对象正在从
循环
迭代器中读取,那么您只需等待看到的第一个对象再次出现(使用
测试is
not
=
)即可终止内部列表


但是如果没有这些知识,就没有任何保证,你选择的任何猜测周期的方法在某些情况下都会失败。

好的,所以我接受@Bakuriu的答案,因为它在技术上是正确的。无法复制/pickle itertools.cycle对象

我已经实现了itertools.cycle的一个子类,是可拾取的(有两个额外的铃铛和哨子要引导)

欢迎反馈


谢谢,

根据您使用循环的方式,您甚至可以使用如下简单的自定义类包装器:

class SmartCycle:
    def __init__(self, x):
        self.cycle = cycle(x)
        self.to_list = x

    def __next__(self):
        return next(self.cycle)
e、 g


你为什么需要这个?要复制实例,只需使用相同的源列表重新创建它(您可以将源列表保存到其他地方)。但是,这将创建一个新的迭代器。请记住,迭代器包含的状态比源iterable多,例如序列中的当前位置。您是否考虑过查看
itertools.tee
?根据您的需要,我认为您可以执行类似于
myiter,copy=itertools.tee(myiter)
说真的,您为什么需要这样做?在这一点上,我倾向于认为你的设计过程中有一个缺陷,不是因为它被禁止了,而是因为它不是循环()的一个特性。而且,
cycle
是用C实现的,所以不容易“破解”内部。
c = FiniteCycle([1, 2, 3])

c.index = -1
print c.next() # prints 3

print [c.next() for _ in xrange(4)] # prints [1, 2, 3, 1]

print c.peek() # prints 2
print c.next() # prints 2

import pickle
import cStringIO
serialised_cycle = pickle.dumps(c)

del c

c = pickle.loads(serialised_cycle)

print c.next() # prints 3
print c.next() # prints 1
class SmartCycle:
    def __init__(self, x):
        self.cycle = cycle(x)
        self.to_list = x

    def __next__(self):
        return next(self.cycle)
> a = SmartCycle([1, 2, 3])
> for _ in range(4):
>     print(next(a))
1
2
3
1

> a.to_list
[1, 2, 3]