Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List comprehension without [ ] in Python

Joining a list:

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

join must take an iterable.

Apparently, join's argument is [ str(_) for _ in xrange(10) ], and it's a list comprehension.

Look at this:

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

Now, join's argument is just str(_) for _ in xrange(10), no [], but the result is the same.

Why? Does str(_) for _ in xrange(10) also produce a list or an iterable?

like image 683
Alcott Avatar asked Jan 30 '12 07:01

Alcott


People also ask

Are list comprehensions necessary?

List comprehensions are useful and can help you write elegant code that's easy to read and debug, but they're not the right choice for all circumstances. They might make your code run more slowly or use more memory.

Is list comprehension possible in Python?

List comprehension in Python is an easy and compact syntax for creating a list from a string or another list. It is a very concise way to create a new list by performing an operation on each item in the existing list. List comprehension is considerably faster than processing a list using the for loop.

What is faster than list comprehension Python?

For loops are faster than list comprehensions to run functions.

Does Python 2.7 have list comprehension?

List comprehensions, a shortcut for creating lists, have been in Python since version 2.0. Python 2.4 added a similar feature – generator expressions; then 2.7 (and 3.0) introduced set and dict comprehensions.


2 Answers

The other respondents were correct in answering that you had discovered a generator expression (which has a notation similar to list comprehensions but without the surrounding square brackets).

In general, genexps (as they are affectionately known) are more memory efficient and faster than list comprehensions.

HOWEVER, it the case of ''.join(), a list comprehension is both faster and more memory efficient. The reason is that join needs to make two passes over the data, so it actually needs a real list. If you give it one, it can start its work immediately. If you give it a genexp instead, it cannot start work until it builds-up a new list in memory by running the genexp to exhaustion:

~ $ 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 

The same result holds when comparing itertools.imap versus map:

~ $ 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 
like image 108
Raymond Hettinger Avatar answered Sep 27 '22 20:09

Raymond Hettinger


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

This is called a generator expression, and is explained in PEP 289.

The main difference between generator expressions and list comprehensions is that the former don't create the list in memory.

Note that there's a third way to write the expression:

''.join(map(str, xrange(10))) 
like image 20
NPE Avatar answered Sep 27 '22 21:09

NPE