2010-09-29 19 views
5

Pour un petit projet sur lequel je travaille, je dois parcourir une liste. Pour chaque élément de ce cycle, je dois commencer un autre cycle à travers la même liste, avec le premier élément comme premier élément du nouveau cycle. Par exemple, je voudrais être en mesure de produire quelque chose comme ceci:Méthode pythonique de copie d'un objet itératif

1, 2, 3, 4, 1, 2, 3, 4, 1, ... 
2, 3, 4, 1, 2, 3, 4, 1, 2, ... 
3, 4, 1, 2, 3, 4, 1, 2, 3, ... 
4, 1, 2, 3, 4, 1, 2, 3, 4, ... 
1, 2, 3, 4, 1, 2, 3, 4, 1, ... 
... 

Je pensais que la copie d'un itertools.cycle après chaque .next() conserverait l'état actuel, afin que je puisse commencer le nouveau cycle avec l'élément du cycle "externe". Ou même "réinitialiser le pointeur de cycle" à une position plus ancienne. J'ai essayé les éléments suivants:

>>> import itertools, copy 
>>> a = itertools.cycle([1, 2, 3, 4]) 
>>> b = copy.copy(a) 

mais eu cette erreur:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/python2.6/copy.py", line 95, in copy 
    return _reconstruct(x, rv, 0) 
    File "/usr/lib/python2.6/copy.py", line 323, in _reconstruct 
    y = callable(*args) 
    File "/usr/lib/python2.6/copy_reg.py", line 93, in __newobj__ 
    return cls.__new__(cls, *args) 
TypeError: cycle expected 1 arguments, got 0 

Je sais qu'il ya beaucoup de façons différentes pour parvenir à ce que je veux, mais je suis à la recherche d'un code court, clair et pythonique. Peut-être que quelqu'un a une autre idée ou même un extrait? Le fait que ce soit not possible to copy iterator objects a réveillé mon intérêt. Y at-il une meilleure pratique dans les situations où l'on veut une copie d'un itérable? Ou copie-t-on des itérations bêtes et inutiles en général?

+1

Ils ne sont pas stupides, [PEP 323] (http://www.python.org/dev/peps/pep-0323/) envisagé de faire itérateurs copiables. – Matt

Répondre

5

Is there a best-practice in situations where one wants a copy of an iterable?

itertools.tee vous donne deux itérateurs que chaque donnent les mêmes éléments que l'original, mais il faut l'original et tout ce qu'il donne mémorise, de sorte que vous ne pouvez pas utiliser la plus originale. Cela n'aiderait pas ici, car il continuerait à mémoriser ces valeurs cyclées jusqu'à ce que vous obteniez un MemoryError.

Or is copying iterables silly and useless in general?

Les itérateurs sont simplement définis pour avoir un état actuel et générer un élément. Vous ne pouvez pas dire s'ils produiront les mêmes articles dans le futur ou quels articles ils ont cités dans le passé. Une vraie copie devrait faire les deux, donc c'est impossible!

Dans votre cas, il est si trivial de faire un nouveau cycle que je préfère faire cela que d'essayer de copier un existant. Par exemple:

def new_cycle(seq, last=None): 
    if last is None: 
     return cycle(seq) 
    else: 
     it = cycle(seq) 
     while next(it) != last: 
      pass 
     return it