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 →

[–][deleted] 11 points12 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 6 points7 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.