Saturday 18 March 2006 — This is almost 19 years old. Be careful.
I was spelunking through the Django source, and noticed two odd idioms (comment mine):
# Apply a function to every item in a list:
tables = [quote_only_if_word(t) for t in tables]
# Make a list of n None's:
l = [None for _ in range(n)]
Both of these use list comprehensions to accomplish jobs that could have been done with older Python facilities:
# Apply a function to every item in a list:
tables = map(quote_only_if_word, tables)
# Make a list of n None's:
l = [None] * n
I’m not saying they should have been done the older way. It’s interesting to see how powerful list comprehensions are that they can displace other language features. I think in this case the new way is clearer for the first statement, and the old way is clearer for the second.
But for a new Python coder, list comprehensions are one tool to understand, compared to the finer-edged but more narrowly-applicable map. So I expect to see more use of list comprehensions like this, and less use of the classic ways.
Comments
Using [None for-in] instead of [None]*n is a really lousy idea, though; it doesn't only use more byte code instructions, you'll also end up doing 2n+2 object allocations and n list reallocations, instead of 3 object allocations. Even for n=1, it's twice as slow. For n=100, it's over 10 times slower under 2.4, and nearly 20 times slower under 2.3.
I'm surprised not only that they created the list of Nones in that slow way, but also that they used range(n) instead of xrange(n). No reason at all to use range() in this case.
Here's one of my worst abuses, to print the first five squares.
[sys.stdout.write(str((lambda y: y*y)(x))+", ") for x in range(1,6)]
Should I have used xrange?
Add a comment: