Python: Если итератор является выражением, рассчитывается ли он каждый раз? - PullRequest
4 голосов
/ 29 июня 2010

Возьмем следующий пример:

>>> for item in [i * 2 for i in range(1, 10)]:
    print item


2
4
6
8
10
12
14
16
18

[i * 2 for i in range(1, 10)] вычисляется ли каждый раз в цикле или только один раз и сохраняется?(Кроме того, каково правильное имя для этой части выражения?)

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

Ответы [ 3 ]

5 голосов
/ 29 июня 2010

Хороший перевод 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 обычно может быть (чуть-чуть) быстрее.

3 голосов
/ 29 июня 2010

Все члены списка выражений вычисляются один раз, а затем повторяются.

В Python 2.x переменная, используемая в LC, просачивается в родительскую область, но поскольку LC уже была оценена, единственное доступное значение - это то, которое используется для генерации последнего элемента в результирующем списке.

3 голосов
/ 29 июня 2010

В этом случае вы создаете список в памяти, а затем перебираете содержимое списка, так что да, он вычисляется один раз и сохраняется. это ничем не отличается от выполнения

i for i in [2,4,6,8]:
   print(i)

Если вы делаете iter (i * 2 для i в xrange (1,10)), вы получаете итератор, который оценивает каждую итерацию.

...