2016-03-18 2 views
1

Следующий код создает некоторые очень странные результатыПреобразование итератора в список изменений итератор

import re 
string = "test test test" 
positions = re.finditer("test", string) 
print (list(positions)) 
print (list(positions)) 

Выход:

[<Match object...>, <Match object...>, <Match object...>] 
[] 

Теперь, я думаю, что я знаю, что здесь происходит. Первый list вызывает «исчерпает» итератор (поэтому он «использует итератор вверх», как в генераторе, в процессе создания списка из итератора), поэтому, когда сделан второй вызов list, итератор ушел и мы получаем пустой список. Это, похоже, подтверждается абзацем ниже, хотя я пытаюсь понять некоторые из вещей, которые они здесь приводят, поэтому я не совсем доволен этим объяснением (если он является правильным):

Объект-контейнер (например, список) создает новый новый итератор каждый раз, когда вы передаете его функции iter() или используете его в цикле for. Попытка этого с помощью итератора будет возвращать тот же исчерпанный объект итератора , который использовался в предыдущем проходе итерации, заставляя его отображаться как пустой контейнер.

Вышеупомянутый абзац от the official documentation.

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

Если кто-нибудь может помочь мне разобраться в путанице здесь, я был бы очень признателен.

Примечание:

Я использую Python 3.5.1

ответ

1

Эта линия:

positions = re.finditer("test", string) 

It returns a one-shot iterator. Затем вы позвонили list(positions)дважды на том же итераторе.

Так что для второго звонка он был уже исчерпан.

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

>>> L = ['a', 'b', 'c'] 
>>> list(L) 
['a', 'b', 'c'] 
>>> list(L) 
['a', 'b', 'c'] 
>>> iter_L = iter(L) # calls L.__iter__() and returns you a one-shot iterator 
>>> list(iter_L) 
['a', 'b', 'c'] 
>>> list(iter_L) 
[] 
+0

одноразовый итератор? –

+0

Да.Вы можете только повторить его один раз. – wim

+0

Хорошо, но это было в значительной степени тем, что я сказал, что я уже думал (что он истощает итератор в первый раз, а затем второй раз). Но, не смотря на это, я думаю, что я понял, что говорится в моем параграфе в моем вопросе. –

0

Когда список() пробегает итератор, он в основном вызывает следующий() на нем, пока он не поднимает StopIteration исключения, а затем присоединяет каждую вещь, которую next() возвращается к списку, а затем возвращает этот список. В основном, реализация списка (ИТЭР) может быть:

my_list(iter): 
    output = [] 
    try: 
     while True: 
      output.append(iter.next()) 
    except StopIteration: 
     return output 

К слову, for петля делает точно то же самое, но вместо того, чтобы output.append(iter.next()) это делает тело цикла.

Смежные вопросы