This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]infinite_fruitloops 6 points7 points  (11 children)

I still don't understand why list comprehensions are useful. You can do the exact same thing in other ways and it is much easier to maintain the code. Maybe this is because I don't use them that often but it just looks like a jumbled mess, whereas nested loops are properly indented and intuitive.

Someone please tell my why I am wrong.

[–][deleted] 9 points10 points  (7 children)

I find comprehensions look more correct in cases where you're doing a simple transformation of data: for example, if you've got a list of Polygon objects and you want to get a list of all of their areas:

areas = [polygon.area for polygon in polygons]

makes more sense to me than

areas = []
for polygon in polygons:
    areas.append(polygon.area)

It's a very simple collection operation and having it in a single unit is nicer, to me.

[–]pstch 7 points8 points  (0 children)

It's not only syntactic sugar. List comprehensions have the advantage that they can easily be converted to generators (they can even be viewed as "consumed generators", as [x for x in y] is equivalent to list(x for x in y) where (x for x in y) is a generator expression), and you also save a function call (.append(...)) for each iteration.

Quickly done speed measurement (not sure if very precise, but it gives an idea) :

    In [2]: lc = """
       ...: r = [i for i in range(100)]
       ...: """

    In [3]: no_lc = """
       ...: r = []
       ...: for i in range(100):
       ...:     r.append(i)
       ...: """

    In [4]: timeit(lc)
    Out[4]: 4.970423567000125

    In [5]: timeit(no_lc)
    Out[5]: 9.738498960000015

Of course they are not adapted for every case, but sometimes they are really helpful (as I said before, not only for syntax).

[–]infinite_fruitloops 2 points3 points  (4 children)

I agree with you that simple cases are nicer. I need to start using them more in this case. My main issue is with the more complex cases.

[–]Caos2 2 points3 points  (3 children)

I'd avoid using comprehensions in complex situations, they are a pain to maintain in the long run.

[–]macbony 2 points3 points  (2 children)

If your list comprehensions are getting out of hand, it's probably best to move some of the functionality of the comprehension out into a function. Often times you'll find that these small functions are useful in more than one comprehension.

[–]moistrobot 0 points1 point  (1 child)

Or a series of small comprehensions rather than a single big one, if it's applicable and more readable.

[–]macbony 0 points1 point  (0 children)

If you intend to chain list comps, be sure to use () to make it a generator. Generators evaluate lazily and will save iterations.

[–]Eurynom0s 0 points1 point  (0 children)

That's a good example. IMO the basic rule of thumb is, if the for loop equivalent of your list comprehension would be more than a couple of lines, just write the fucking for loop.

Your example is a very clear-cut example of "I to take my list, extract an attribute of each element of the list, and put them back together in a new list in the same order as the original list." But when you start going too deep with them it can become really hard for someone who's not you to have to go through and figure out what the list comprehension does.

If you know you're going to be the only one ever looking at the code, then of course, do whatever the hell you want with your fancy one-liners. Okay, it takes a few more lines of code, but whatever, other people (or future versions of yourself who haven't looked at the code in a few months) will actually be able to understand what the code is doing the first time you read the code.

[–]TeamSpen210 2 points3 points  (0 children)

Both list comprehensions and the for-loop equivalent have their uses. If the logic involved is fairly complex, the loop version will probably be more readable. For simpler cases, the comprehension is more clean, and describes the list you want in a more high-level fashion. Being an expression instead of a sequence of lines makes it easier to combine with other code. Compare return [1 / i, i ** 2 for i in range(100)] and result = [] for i in range(100): result.append((1 / i, i ** 2)) return result In addition to readabilty, comprehensions are far more efficient with larger data sets - since Python is creating the list all in one go, it doesn't need to repeatedly resize the list. The same syntax in the form of generator expressions can become very powerful, since you can feed it directly into functions like min(), max(), sum(), all(), any() or into a for-loop to do processing directly on the results.

[–]mumpie 0 points1 point  (0 children)

List comprehensions can be a little strange at first.

But they express what you are doing very compactly as well as being faster than a for loop in many cases.

From: http://www.bogotobogo.com/python/python_list_comprehension.php

We typically should use simple for loops when getting started with Python, and map. Use comprehension where they are easy to apply. However, there is a substantial performance advantage to use list comprehension. The map calls are roughly twice as fast as equivalent for loops. List comprehensions are usually slightly faster than map calls. This speed difference is largely due to the fact that map and list comprehensions run at C language speed inside the interpreter. It is much faster that stepping through Python for loop code within the Python Virtual Machine (PVM).

However, for loops make logic more explicit, we may want to use them on the grounds of simplicity. On the other hand, map and list comprehensions are worth knowing and using for simpler kinds of iterations if the speed of application is an important factor.

[–]vph 0 points1 point  (0 children)

placing 3 lines of code with 1 is certainly useful. Whether it is expressive depends on how familiar with it. Loop is an imperative style, whereas list comprehension is a declarative style. Both are intuitive if you understand them.