views:

439

answers:

7

Which of the following is better to use and why?

Method 1:

for k, v in os.environ.items():
       print "%s=%s" % (k, v)

Method 2:

print "\n".join(["%s=%s" % (k, v) 
   for k,v in os.environ.items()])

I tend to lead towards the first as more understandable, but that might just be because I'm new to Python and list comprehensions are still somewhat foreign to me. Is the second way considered more Pythonic? I'm assuming there's no performance difference, but I may be wrong. What would be the advantages and disadvantages of these 2 techniques?

(Code taken from Dive into Python)

+4  A: 

The first one in my opinion, because:

  • It doesn't build a huge string.
  • It doesn't build a huge list (can easily be fixed with a generator, by removing the []).

In both cases, you access the items in the same way (using the dictionary iterator).

Bastien Léonard
+2  A: 

list comprehensions are supposed to be run at C level, so if there is huge loop, list comprehensions are good choice.

S.Mark
+10  A: 

I find the first example better - less verbose, clearer and more readable.

In my opinion, go with what best gets your intention across, after all:

Programs should be written for people to read, and only incidentally for machines to execute.

-- from "Structure and Interpretation of Computer Programs" by Abelson and Sussman

By the way, since you're just starting to learn Python, start learning the new String Formatting syntax right away:

for k, v in os.environ.items():
    print "{0}={1}".format(k, v)
Tim Pietzcker
+1. Absolutely - go for readability first. Optimize for performance if and when...
Yuval A
please note that str.format() is present only in python ver >= 2.6
Nas Banov
+17  A: 

The particular code examples you have chosen do not demonstrate any advantage of the list comprehension, because it is being (mis-)used for the trivial task of printing. In this simple case I would choose the simple for loop.

In many other cases, you will want to supply an actual list to another function or method, and the list comprehension is the easiest and most readable way to do that.

An example which would clearly show the superiority of the list comp could be made by replacing the print example with one involving creating another actual list, by appending to one on each iteration of the for loop:

L = []
for x in range(10):
    L.append(x**2)

Gives the same L as:

L = [x**2 for x in range(10)]
Ben James
the problem with your example is that it is trivial. Why not actually use the code in the question to show the differences? Possibly with some timing info?
Adriano Varoli Piazza
Another benefit is that you can supply the resulting list to another function, or chain/nest comprehensions.
klochner
+7  A: 

If the iteration is being done for its side effect ( as it is in your "print" example ), then a loop is clearer.

If the iteration is executed in order to build a composite value, then list comprehensions are usually more readable.

Steven D. Majewski
+1: list comprehensions hail from functional programming, while for-loops hail from imperative programming.
badp
+1 for a concise and simple explanation of when to use loops vs. list comprehensions.
Brian
I agree about readability, but readable is not the primary consideration in real world code. maybe in demo code readability is king. performance is sometimes king in the real world, although not always. generators are used, when used, because they confer some benefit. The OP asked "which is better". Which ever gets the job done in a manifestly better way (less wasteful of resources in some cases, faster in some cases, as your requirements dictate).
Warren P
I would initially go for readability unless there's a reason not to.In the example given, there's no reason to try to speed up the print by a few microseconds. In the more general case, if you're iterating for the side effects of the expression, it's quite likely that the side effect producing statement takes more time than the iteration construct you use.
Steven D. Majewski
+3  A: 

List comprehension is more than twice as fast as explicit loop. Base on Ben James' variation, but replace the x**2 with a more trivial x+2 function, the two alternatives are:

def foo(n):
  L = []
  for x in xrange(n):
    L.append(x+2)
  return L


def bar(n):
  return [x+2 for x in xrange(n)]

Timing result:

In [674]: timeit foo(1000)
10000 loops, best of 3: 195 us per loop

In [675]: timeit bar(1000)
10000 loops, best of 3: 81.7 us per loop

List comprehension wins by a large margin.

I agree than readability should be a priority over performance optimization. However readability is in the eye of beholder. When I first learn Python, list comprehension is a weird thing I find hard to comprehend! :-O But once I got use to it, it becomes a really nice short hand notation. If you are to become proficient in Python you have to master list comprehension.

Wai Yip Tung
Exactly, with list comprehensions you are writing more high-performance code, which will be understood by advanced pythonistas, and not so much, by the first-year students.
Warren P
list comprehensions express the actual logic better, close to set builder notation. A for loop has to be "executed in the head" to see what it does, in general.
kaizer.se
I haven't tried in actual Python, but your example code looks as if the performance gain could be made arbitrarily large by increasing n: Unless Python does something to counter this effect, foo uses an O(n^2) algorithm, while bar runs in O(n).
Christopher Creutzig
foo is O(n) just as bar. Python's list.append is O(1).
Wai Yip Tung
+2  A: 

I agree with @Ben, @Tim, @Steven:

  • readability is the most important thing (do "import this" to remind yourself of what is)
  • a listcomp may or may not be much faster than an iterative-loop version... it depends on the total number of function calls that are made
  • if you do decide to go with listcomps with large datasets, it's better to use generator expressions instead

Example:

print "\n".join("%s=%s" % (k, v) for k,v in os.environ.iteritems())

in the code snippet above, I made two changes... I replaced the listcomp with a genexp, and I changed the method call to iteritems(). [this trend is moving forward as in Python 3, iteritems() replaces and is renamed to items().]

wescpy
Why is readability the MOST important thing, always, for everyone?
Warren P
it's a pay-it-forward type of mentality that makes such code "Pythonic...," being kind and respectful of your fellow programmers, esp. since your code will likely outlive you at your place of employment. it's hard to explain well in words. again, check out "import this"... the Zen of Python gives you general guidelines as they pertain to Python's philosophy.
wescpy
@Warren: Because readability leads to maintainability and readability makes performance improvements that much easier. Never forget to concentrate on those parts where your profiler points to when optimizing.
Christopher Creutzig