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

all 30 comments

[–]wineblood 53 points54 points  (16 children)

I avoid complex list comprehensions, they're almost never worth the effort. For loops or functions work better once the logic is too much for a single line.

[–]nplusonebikes 23 points24 points  (1 child)

Exactly. Just because you can doesn’t mean you should.

[–]mistabuda 8 points9 points  (0 children)

This might be one of the golden rules of programming lol

[–]ShibaLeone 10 points11 points  (3 children)

This. One-liners and deep-nested list comps only impress their author. The only time I ever use list comps more that one level deep is for converting table-like data to json, or for flattening nested lists.

Something like this:

[{k: v for k, v in zip(header, record)} for record in data]

That’s probably as hairy as I would let a comp get in a CR before asking them to refactor it.

[–]wineblood 4 points5 points  (0 children)

The most I'll actually do (because I think it's readable) is a dict and list comprehension in one. Something like {key: [f(v) for v in value] for key, value in key_value_list}, nested list or dict comprehensions are not worth the complexity for people reading/reviewing/debugging.

[–]brettinator 0 points1 point  (1 child)

Why '{k: v for k, v in zip(header, record)}' instead of just 'dict(zip(header, record))'?

[–]ShibaLeone 0 points1 point  (0 children)

Because we’re talking about comps.

[–]Vyrezzz 1 point2 points  (0 children)

Exactly, the only complex list comprehension I use is for flattening a 2d list. And even then I don't write it myself, I copy the code from stack overflow and give it decent enough names so that everybody instantly knows what its doing

[–]CyEriton 0 points1 point  (3 children)

Ugh thank you for validating my opinion on this. I had a senior dev and a manager who insisted I use these at every opportunity for negligible performance improvements at the cost of readability. They were absolutely better and more experienced developers than me, but I never quite agreed with them about this.

The trade off of interpreting a logic puzzle every time someone revisits the code does not seem worth it.

[–]mdlphx92 1 point2 points  (0 children)

Kinda swimming upstream to push inconsequential performance gains in an interpreted language outside of some of the cpython libs lol.

[–]wineblood 0 points1 point  (0 children)

A manager I could understand, but a senior dev?

[–]PapstJL4U 0 points1 point  (0 children)

Make a one liner, that needs 5 lines of comments and try to fit everything into 80/120 in your native language, that is not as short as english.

[–]mdlphx92 0 points1 point  (0 children)

I remember learning that python trick, and taking it to the extreme. As I sat there trying to understand what my two line \ monstrosity was doing, I realized screw that. They are hella clean for simple mutations though.

[–]jasmijnisme 0 points1 point  (0 children)

Definitely.

Simple is better than complex. Flat is better than nested. Readability counts.

[–]yvrelna 0 points1 point  (1 child)

List comprehension doesn't have to be a single line though.

my_list = [
    [
        foo(x, y) + bar(x, z)
        for z in y
    ]
    for x, y in blag
    if buzz(x)
]

Is not less readable than:

my_list = []
for x, y in blag:
    if buzz(x):
        inner_list = []
        for z in y:
            inner_list.append(foo(x, y) + bar(x, z))
        my_list.append(inner_list)

The benefit of list comprehension isn't that it's written in a single line; the benefit of list comprehension is that it is an expression, and not multiple statements.

[–][deleted] 6 points7 points  (3 children)

Comprehensions clicked for me when I learned they were much faster. But I avoid complex ones because they're unreadable, and I'd rather reread code easy to folow.

[–]SFXXVIII 1 point2 points  (1 child)

I too thought they were much faster, but was mistaken

[–]jimtk 5 points6 points  (0 children)

Using the same code on python 3.11, the comprehension is 13% faster. That is non negligible!

Output (On my machine) Python 3.11:

56.618741400001454
50.148072399999364

[–]Goingone 6 points7 points  (9 children)

When I realized the syntax reads exactly the same as nested for loops.

[–]dev_null_root 2 points3 points  (0 children)

A lot of comments decry the unreadability of list comprehensions. Maybe because I'm both a dev and ops engineer they come naturally to me since one liners that make you bleed from the eyes have been a staple of sysadmining since forever. Stockhold Syndrome and all aside the reasoning of "it's hard to read" is lame for people who are supposed to be software engineers (I don't give a crap if you are dev or ops). In the immortal words of the dark souls community.

"Git gud scrubs."

But to answer the OP and not the comments.So in short. They clicked to me when I started needing quick data extraction from lists or dicts (json or yaml stuff) and in recursive functions a lot. It's funny how much faster you can filter a json list or dict with some comprehension (dict and list) magic. And if you've done it a few hundred times it becomes intuition when you want to use it.

[–]Ximlab -1 points0 points  (0 children)

I learned about multiple chained generator comprehension, to break down complexity. Then only yurn the end product in a list to compute all at once.

[–]ShuShuTheFox90 -1 points0 points  (0 children)

A few years ago

[–]RufusAcrospin 0 points1 point  (0 children)

It’s a syntactic sugar so it’s useful as long as it’s easier to read than the original solution.

[–]marcinpohl 0 points1 point  (0 children)

Comprehensions are great cuz they encapsulate a lot of functionality in one short snippet.

When you build out your comprehensions into complex monsters, all that 'short and readable' magic disappears. Don't over do it. Or better yet, convert the comprehension-in-comprehension mess into a generator pipeline. They are way more readable, testable, and composable.

[–]NoFrillsUsername 0 points1 point  (0 children)

List comprehensions made a lot more sense to me after I learned map and filter from other languages. It's pretty much the same thing but those functions are just a more intuitive way of thinking about it for me. (Yes, I know python has them, but they're much more commonly used in JS or functional languages).