Перезапись итератора с помощью itertools.tee - PullRequest
1 голос
/ 27 марта 2020

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

Если я вызываю tee в том же блоке, что и итератор, то это кажется безопасным:

my_iter = create_some_iterator()

my_iter, my_lookahead = itertools.tee(my_iter)

, поскольку исходный итератор, на который указывает my_iter, имеет (I предположим, что больше нет счетчиков ссылок, и my_iter теперь указывает на его дубликат, поэтому нет возможности использовать исходный итератор.

Но верно ли это, если я пропущу его через функцию?

def foo(some_iter):
    some_iter, some_lookahead = itertools.tee(some_iter)
    # Do some lookahead tasks

my_iter = create_some_iterator()
foo(my_iter)
next(my_iter)   # Which iter is this?

Указывает ли my_iter на копию my_iter после выхода из функции? Или это все еще указывает на оригинальный итератор, который я не должен использовать?

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


Это то, что id говорит мне в приведенном выше примере, что говорит о том, что я не могу использовать итераторы таким образом, но я также могу неправильно истолковывать, что id означает здесь:

import itertools

def foo(some_iter):
    print('  some_iter id:', id(some_iter))
    some_iter, some_lookahead = itertools.tee(some_iter)

    print('  new some_iter id:', id(some_iter))
    print('  some_lookahead id:', id(some_lookahead))
    # Do some lookahead tasks

my_iter = iter(range(10))
print('my_iter id:', id(my_iter))
foo(my_iter)

print('my_iter id after foo:', id(my_iter))

Вывод:

my_iter id: 139686651427120
  some_iter id: 139686651427120
  new some_iter id: 139686650411776
  some_lookahead id: 139686650411712
my_iter id after foo: 139686651427120

my_iter все еще имеет свой исходный id, а не тот, который назначен some_iter с помощью tee.


ОБНОВЛЕНИЕ: Извините, я не хотел задавать этот вопрос. Я более или менее отвечаю на него сам во второй части.

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

Также наполовину пытался спросить, как решить эту проблему, но этот ответ дает решение.

Я пытался уменьшить вопрос, но слишком сильно уменьшил его .

Я пытался закрыть этот вопрос, но он мне больше не позволил, поэтому не уверен, как с этим справиться. Извинения тем, кто уже ответил.

Ответы [ 2 ]

0 голосов
/ 27 марта 2020

В Python, передача чего-либо в функцию никогда делает копию.

def identity(x):
    return x

iter1 = iter(range(10))
iter2 = identity(iter1)
assert iter1 is iter2  # assert "object equality"

Python функции всегда работают таким образом.

Поведение itertools.tee не имеет значения. Тот факт, что мы имеем дело именно с итераторами, не имеет значения.

Тот факт, что itertools.tee возвращает копию , определяет поведение c itertools.tee.

Если у вас есть немного свободного времени, этот доклад может быть очень полезным: https://www.youtube.com/watch?v=_AEJHKGk9ns

0 голосов
/ 27 марта 2020

Указывает ли my_iter на копию my_iter после выхода из функции? Или это все еще указывает на оригинальный итератор, который я не должен использовать?

Это все еще указывает на оригинал. Python - это язык «передачи по значению» (хотя все его значения являются ссылками, поэтому иногда это немного сбивает с толку). Это не язык передачи по ссылке, назначение параметра является чисто локальным для функции и невидимым для вызывающей стороны.

...