Понимание списка без [] в Python - PullRequest
71 голосов
/ 30 января 2012

Присоединение к списку:

>>> ''.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), нет [], но результат тот же.

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

Ответы [ 7 ]

123 голосов
/ 30 января 2012

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

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

ОДНАКО, в случае ''.join(), списки понимаются быстрее и эффективнее памяти.Причина в том, что join должен сделать два прохода по данным, поэтому ему действительно нужен реальный список.Если вы дадите ему один, он может начать свою работу немедленно.Если вместо этого вы дадите ему genexp, он не сможет начать работу, пока не создаст новый список в памяти, запустив 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
57 голосов
/ 30 января 2012
>>>''.join( str(_) for _ in xrange(10) )

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

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

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

''.join(map(str, xrange(10)))
5 голосов
/ 30 января 2012

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

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

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

5 голосов
/ 30 января 2012

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

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

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

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

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

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

4 голосов
/ 30 января 2012

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

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

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

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

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

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

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

0 голосов
/ 30 января 2012

Аргументом для вашего второго join вызова является выражение генератора. Он производит итеративный.

0 голосов
/ 30 января 2012

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

...