2013-11-20 2 views
0

Предполагается: при использовании python itertools.tee() все повторяющиеся итераторы ссылаются на исходный итератор, а оригинал кэшируется для повышения производительности.Python itertools tee, клоны и кеширование

Мое основное беспокойство в следующем запросе касается МОЙ ИДЕИ Предполагаемое/правильное поведение кэширования.
Редактировать: моя идея правильное кэширование было основано на ошибочных функциональных предположениях. В конечном итоге понадобится небольшая обертка вокруг тройника (что, вероятно, будет иметь последствия для кэширования).


Вопрос:

Допустим, я создаю 3 итераторов клонов с использованием тройника: a, b, c = itertools.tee(myiter,3). Также предположим, что на этом этапе я удаляю все ссылки на оригинал, myiter (это означает, что для моего кода нет ссылки на исходный текст в будущем).

В какой-то более поздний момент в коде, если я решил, что хочу еще один клон myiter, могу ли я просто переименовать() один из моих дубликатов? (При правильном кэшировании обратно первоначально кэшируются myiter)

Другими словами, в какой-то позже, я хочу я вместо этого использовал: a, b, c, d = itertools.tee(myiter,4). Но, так как я отбросили все ссылки на оригинальный myiter, лучшее, что я могу собрать бы: copytee = itertools.tee(a, 1) #where 'a' is from a previous tee()

тройник() знаю, что я хочу ли здесь? (Что я действительно хочу, чтобы создать клон на основе оригинальной myiter, НЕ промежуточный клон a (который может быть частично потребляются))

+0

Пробовали ли вы делать это? Если это не сработало, сообщите об этом в сообщении об ошибке. – thefourtheye

+0

Мой итератор работает нормально, но я не могу подтвердить, переносит ли кеширование к второму клону. Я планирую использовать это на огромном итераторе и хочу убедиться, что я делаю это правильно. – user2097818

ответ

6

Там нет ничего магического tee. Это просто умно ;-) В любой point, tee клонирует итератор, переданный ему. Это означает, что клонированный итератор (ы) даст значения, полученные итератором прошедшего времени с этого момента на. Но для них невозможно воспроизвести значения, которые были произведено доtee было вызвано.

Покажем это с чем-то гораздо проще, чем ваш пример:

>>> it = iter(range(5)) 
>>> next(it) 
0 

0 уже нет - навсегда. tee() не может получить его обратно:

>>> a, b = tee(it) 
>>> next(a) 
1 

Так a толкнул it производить его следующее значение. Это, что значение, которое получает в кэше, так что другие клоны могут воспроизвести его тоже:

>>> next(b) 
1 

Чтобы получить этот результат, it не тронул - 1 было получено из внутреннего кэша. И теперь, когда все it, a и b произвели 1, 1 тоже пропало.

Я не знаю, что отвечает ли ваш вопрос - «Есть ли тройник() знаю, что я хочу здесь» отвечать кажется, требует телепатии ;-) То есть, я не знаю, что вы подразумеваете под «с правильным кэшированием». Было бы очень полезно, если бы вы дали точный пример поведения ввода/вывода, на которое вы надеетесь.

Короткие этого, документы Python не дают код Python, что эквивалентно тройника(), и, возможно, изучая, что бы ответить на ваш вопрос:

def tee(iterable, n=2): 
    it = iter(iterable) 
    deques = [collections.deque() for i in range(n)] 
    def gen(mydeque): 
     while True: 
      if not mydeque:    # when the local deque is empty 
       newval = next(it)  # fetch a new value and 
       for d in deques:  # load it to all the deques 
        d.append(newval) 
      yield mydeque.popleft() 
    return tuple(gen(d) for d in deques) 

Вы можете видеть из этого, например, что ничего о внутреннее состояние итератора кэшируется - все, что кэшируется это значение производится по переданным в итераторе, начиная с момента tee() называется. Каждый клон имеет свой собственный deque (список FIFO) значений переданного итератора, созданных до сих пор, и это все клоны знают об итераторе с передачей. Так что это может быть слишком просто для всех, на что вы действительно надеетесь.

+0

Клон второй руки ничего не знает об исходном итераторе. Он будет производить только значения, создаваемые итератором 1-й стороны, - и вы не должны снова использовать итератор с 1-й рукой! Так же, как вы не должны использовать 'it' снова после создания 1-го' 'tee (it)' клонов. И в любом случае нет «оригинального итеративного дека» - есть один deque * на клон *, все независимые друг от друга. Извините, но я все еще не совсем понимаю, что означает «правильно кэшированный». Дайте точный желаемый пример ввода/вывода или откажитесь от этого ;-) –

+0

Ваш последний пример пролил много света на эту проблему. Мое представление о правильном кэшировании было бы: клонирование клона, где новый deque ссылался на исходный iter deque. По-видимому, ясно, что этого не происходит ... по крайней мере. Пока мой 1-й клон не потребляет его значения, 2-я рука будет, по сути, правильно кэшироваться. Если на 1-й руке было какое-либо потребление, любые клоны, сделанные после этого, не будут правильно отражать исходный иттер (скорее, частично поглощенный 1-й рукой). – user2097818

+0

извините за репост. Вы ответили на этот вопрос. Моя идея ** правильного кэширования ** действительно нуждается в новой теме. – user2097818