Подтвердить что ты не робот

Понимание списков Python для циклов

Я читаю Pikon wikibook и смущаюсь в этой части:

Описание списка поддерживает более одного для оператора. Это будет последовательно оценивать элементы во всех объектах и ​​циклически над более короткими объектами, если один объект длиннее остальных.

>>>item = [x+y for x in 'cat' for y in 'pot']
>>>print item
['cp', 'co', 'ct', 'ap', 'ao', 'at', 'tp', 'to', 'tt']

Я понимаю использование вложенных циклов, но я не получаю

... и будет цикл над более короткими объектами, если один объект длиннее остальных

Что это значит? (короче, длиннее...)

4b9b3361

Ответ 1

Просто попробуйте:

>>> [x+y for x in 'cat' for y in 'potty']
['cp', 'co', 'ct', 'ct', 'cy', 'ap', 'ao', 'at', 'at', 'ay', 'tp', 'to', 'tt', 'tt', 'ty']
>>> [x+y for x in 'catty' for y in 'pot']
['cp', 'co', 'ct', 'ap', 'ao', 'at', 'tp', 'to', 'tt', 'tp', 'to', 'tt', 'yp', 'yo', 'yt']

внутренний 'x' в рассмотренном списке выше (т.е. часть for x in 'cat') совпадает с внешним for x in 'cat': в этом примере:

>>> li=[]
>>> for x in 'cat':
...    for y in 'pot':
...       li.append(x+y)
# li=['cp', 'co', 'ct', 'ap', 'ao', 'at', 'tp', 'to', 'tt']

Таким образом, эффект создания одного короче или дольше такой же, как и цикл "x" или "y" длиннее в двух вложенных циклах:

>>> li=[]
>>> for x in 'catty':
...    for y in 'pot':
...       li.append(x+y)
... 
>>> li==[x+y for x in 'catty' for y in 'pot']
True

Edit

Кажется, что путаница (в комментариях) о вложенных циклах против zip.

Вложенные петли:

Как показано выше, это:

[x+y for x in '12345' for y in 'abc']

- это то же самое, что два вложенных цикла 'for' с 'x' внешним циклом.

Вложенные циклы будут выполнять внутренний цикл y в диапазоне x во время внешнего цикла.

Итак:

>>> [x+y for x in '12345' for y in 'ab']
    ['1a', '1b',   # '1' in the x loop
     '2a', '2b',   # '2' in the x loop, b in the y loop
     '3a', '3b',   # '3' in the x loop, back to 'a' in the y loop
     '4a', '4b',   # so on
     '5a', '5b'] 

Вы можете получить тот же результат с product от itertools:

>>> from itertools import product
>>> [x+y for x,y in product('12345','ab')]
['1a', '1b', '2a', '2b', '3a', '3b', '4a', '4b', '5a', '5b']

Zip аналогичен, но останавливается после исчерпания более короткой последовательности:

>>> [x+y for x,y in zip('12345','ab')]
['1a', '2b']
>>> [x+y for x,y in zip('ab', '12345')]
['a1', 'b2']

Вы можете использовать itertools для zip, который будет застегиваться до тех пор, пока не будет исчерпана самая длинная последовательность, но результат будет другим:

>>> import itertools
>>> [x+y for x,y in itertools.zip_longest('12345','ab',fillvalue='*')]
['1a', '2b', '3*', '4*', '5*'] 

Ответ 2

Ну, в документации Python не говорится о таком коротком/длинном случае: http://docs.python.org/2/tutorial/datastructures.html#list-comprehensions. Наличие двух "за" в понимании списка означает наличие двух циклов. Пример, обозначенный @drewk, верен.

Позвольте мне скопировать его для объяснения:

>>> [x+y for x in '123' for y in 'pot']
['1p', '1o', '1t', '2p', '2o', '2t', '3p', '3o', '3t']
>>>
>>> [x+y for x in '1' for y in 'pot']
['1p', '1o', '1t']
>>>

В обоих случаях первый "for" формирует внешний цикл, а hte второй "for" формирует внутренний цикл. Это единственный инвариант здесь.