Просмотр списка без [] в Python

Объединение списка:

>>> ''.join([ str(_) for _ in xrange(10) ])
'0123456789'

join должен выполнять итерацию.

По-видимому, аргумент join имеет значение [ str(_) for _ in xrange(10) ], и это описание .

Посмотрите на это:

>>>''.join( str(_) for _ in xrange(10) )
'0123456789'

Теперь аргумент join равен str(_) for _ in xrange(10), no [], но результат тот же.

Почему? Создает ли str(_) for _ in xrange(10) список или итерируемый?

Ответ 1

>>>''.join( str(_) for _ in xrange(10) )

Это называется выражением генератора и объясняется в PEP 289.

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

Обратите внимание, что существует третий способ записи выражения:

''.join(map(str, xrange(10)))

Ответ 2

Другие респонденты были правильны в ответе на то, что вы обнаружили выражение generator (которое имеет нотацию, похожую на списки, но без окружающих квадратных скобок).

В общем, genexps (как они ласково известны) более эффективны в памяти и быстрее, чем понимание списков.

ОДНАКО, это случай ''.join(), понимание списка быстрее и эффективнее. Причина в том, что для соединения требуется сделать два прохода над данными, поэтому на самом деле нужен реальный список. Если вы его дадите, он сразу начнет свою работу. Если вы дадите ему генкс вместо этого, он не сможет начать работу до тех пор, пока не создаст новый список в памяти, запустив genexp для исчерпания:

~ $ python -m timeit '"".join(str(n) for n in xrange(1000))'
1000 loops, best of 3: 335 usec per loop
~ $ python -m timeit '"".join([str(n) for n in xrange(1000)])'
1000 loops, best of 3: 288 usec per loop

Тот же результат выполняется при сравнении itertools.imap по сравнению с картой:

~ $ python -m timeit -s'from itertools import imap' '"".join(imap(str, xrange(1000)))'
1000 loops, best of 3: 220 usec per loop
~ $ python -m timeit '"".join(map(str, xrange(1000)))'
1000 loops, best of 3: 212 usec per loop

Ответ 3

Второй пример использует выражение генератора, а не понимание списка. Разница в том, что при понимании списка список полностью строится и передается на .join(). С выражением генератора элементы генерируются один за другим и потребляются .join(). Последний использует меньше памяти и обычно быстрее.

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

[str(n) for n in xrange(10)]

- это просто "синтаксический сахар" для:

list(str(n) for n in xrange(10))

Другими словами, понимание списка - это просто выражение генератора, которое превращается в список.

Ответ 4

Если это в parens, но не в скобках, это технически выражение генератора. Выражения генератора были впервые введены в Python 2.4.

http://wiki.python.org/moin/Generators

Часть после объединения, ( str(_) for _ in xrange(10) ) является, само собой, выражением генератора. Вы можете сделать что-то вроде:

mylist = (str(_) for _ in xrange(10))
''.join(mylist)

и это означает то же самое, что вы писали во втором случае выше.

Генераторы имеют некоторые очень интересные свойства, не в последнюю очередь из-за того, что они не заканчивают выделение целого списка, когда он вам не нужен. Вместо этого такая функция, как объединение, "накачивает" элементы из выражения генератора по одному, делая свою работу на крошечных промежуточных частях.

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

Ответ 5

Как уже упоминалось, это выражение генератора.

Из документации:

Скобки могут быть опущены при вызовах только с одним аргументом. Смотрите раздел Звонки для подробностей.

Ответ 6

Это генератор, а не понимание списка. Генераторы также являются итерабельными, но вместо того, чтобы сначала создавать весь список, а затем передавать его для соединения, он передает каждое значение в xrange один за другим, что может быть намного более эффективным.

Ответ 7

Аргумент второго вызова join является выражением генератора. Это делает итерабельным.