Хороший перевод for i in <whatever>: <loopbody>
, показывающий, что именно он делает для любой <whatever>
и любой <loopbody>
:
_aux = iter(<whatever>)
while True:
try: i = next(_aux)
except StopIteration: break
<loopbody>
за исключением того, что псевдопеременная, которую я здесь назвал _aux
, на самом деле остается безымянной.
Таким образом, <whatever>
всегда вычисляется только один раз (чтобы получить из него iter()
), и результирующий итератор будет next
редактироваться до тех пор, пока он не закончится (если в <loopbody>
нет break
).
При использовании listcomp, который вы использовали, при оценке создается объект list
(который в вашем примере кода остается безымянным). В очень похожем коде:
for item in (i * 2 for i in range(1, 10)): ...
с использованием genexp вместо listcomp (синтаксически, круглые скобки вместо квадратных скобок listcomp), именно next()
выполняет большую часть работы (продвигая i
и удваивая его) вместо объединения всей работы во время построения - это занимает меньше временной памяти и может сэкономить время, если разумное тело тела может с большой вероятностью break
выйти раньше, но за исключением таких особых условий (очень ограниченная память или вероятное раннее завершение цикла), listcomp обычно может быть (чуть-чуть) быстрее.