Pythonic способ копирования повторяемого объекта - PullRequest
5 голосов
/ 30 сентября 2010

Для небольшого проекта, над которым я работаю, мне нужно перебрать список.Для каждого элемента этого цикла я должен начать другой цикл через тот же список, с первым элементом в качестве первого элемента нового цикла.Например, я хотел бы иметь возможность создать что-то вроде этого:

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, ...
...

Я думал, что копирование itertools.cycle после каждого .next () сохранит текущее состояние, так что я могу начатьновый цикл с элементом из «внешнего» цикла.Или даже «сбросить указатель цикла» на более старую позицию.Я попробовал следующее:

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

, но получил эту ошибку:

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

Я знаю, что есть много разных способов достичь того, чего я хочу, но я ищу какой-то короткий, ясныйи питонический код.Может быть, у кого-то есть другая идея или даже фрагмент?Меня заинтересовал тот факт, что невозможно скопировать объекты итератора .Есть ли лучшая практика в ситуациях, когда требуется копия итерируемого?Или копирование итераций глупо и вообще бесполезно?

1 Ответ

5 голосов
/ 30 сентября 2010

Есть ли передовой опыт в ситуациях, когда требуется копия итерируемого?

itertools.tee дает вам два итератора, каждый из которых выдает те же элементы, что и оригинал, ноон берет оригинал и запоминает все, что дает, так что вы больше не можете использовать оригинал.Это не помогло бы, хотя, потому что это продолжало бы запоминать эти циклические значения, пока вы не получите MemoryError.

Или копирование итераций глупо и бесполезно в целом?* итераторы просто определены, чтобы иметь текущее состояние и выдавать элемент.Вы не можете сказать, будут ли они давать те же предметы в будущем или какие предметы они приносили в прошлом.Реальная копия должна была бы делать и то и другое, поэтому это невозможно!

В вашем случае настолько просто создать новый цикл, что я бы предпочел сделать это, чем пытаться скопировать существующий.Например:

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