Тем не менее, существует важное семантическое различие между этими двумя ...
Не совсем смыслово или важно. Они оба повторяемы - они оба работают с оператором for.
Разница, например, важна, когда нужно многократно повторять цикл.
Когда это произойдет? Вы должны быть более конкретными. В тех редких случаях, когда вам нужно сделать два прохода через итеративную коллекцию, часто бывают лучшие алгоритмы.
Например, допустим, вы обрабатываете список. Вы можете перебирать список, сколько хотите. Почему вы запутались с итератором вместо итерируемого? Хорошо, это не сработало.
Хорошо, вот один. Вы читаете файл в два прохода, и вам нужно знать, как сбросить итерацию. В данном случае это файл, и seek
требуется; или закрыть и открыть заново. Это кажется неприглядным. Вы можете readlines
получить список, который позволяет два прохода без сложности. Так что в этом нет необходимости.
Подождите, что если у нас будет такой большой файл, что мы не сможем прочитать все это в память? И по непонятным причинам мы тоже не можем искать. Что тогда?
Теперь мы дошли до мельчайших двух проходов. На первом проходе мы что-то накопили. Индекс или резюме или что-то. Индекс содержит все данные файла. Резюме часто представляет собой реструктуризацию данных. С небольшим изменением от «сводки» до «реструктуризации» мы сохранили данные файла в новой структуре. В обоих случаях нам не нужен файл - мы можем использовать индекс или сводку.
Все «двухпроходные» алгоритмы могут быть заменены на один проход исходного итератора или итерируемый и второй проход другой структуры данных.
Это не LYBL или EAFP. Это алгоритм проектирования. Вам не нужно сбрасывать итератор - YAGNI.
Редактировать
Вот пример итератора / итерируемой проблемы. Это просто плохо разработанный алгоритм.
it = iter(xrange(3))
for i in it: print i,; #prints 1,2,3
for i in it: print i,; #prints nothing
Это тривиально исправлено.
it = range(3)
for i in it: print i
for i in it: print i
«Несколько раз параллельно» тривиально исправлено. Напишите API, который требует итерируемого. И когда кто-то отказывается читать документацию API или отказывается следовать ей после прочтения, его вещи ломаются. Как и должно быть.
«Приятно защищать от случая, когда пользователь предоставляет только итератор, когда требуется несколько проходов», - оба примера безумных людей, пишущих код, нарушающий наш простой API.
Если кто-то достаточно безумен, чтобы прочитать больше всего (но не все документы по API) и предоставить итератор, когда итерация была требуется , вам нужно найти этого человека и научить его (1), как прочитайте всю документацию по API и (2) следуйте документации по API.
Проблема "защиты" не очень реалистична. Эти сумасшедшие программисты замечательно редки. И в тех немногих случаях, когда это происходит, вы знаете, кто они и могут им помочь.
Редактировать 2
Алгоритмы «мы должны читать одну и ту же структуру несколько раз» являются фундаментальной проблемой.
Не делай этого.
for element in someBigIterable:
function1( element )
for element in someBigIterable:
function2( element )
...
Сделайте это вместо этого.
for element in someBigIterable:
function1( element )
function2( element )
...
Или рассмотрим что-то вроде этого.
for element in someBigIterable:
for f in ( function1, function2, function3, ... ):
f( element )
В большинстве случаев такого рода «стержень» ваших алгоритмов приводит к программе, которую легче оптимизировать и которая может привести к чистому улучшению производительности.