5 ms·
What is awful about: foo = [transform(bar) for bar in baz.list() if condition(bar)] ? Seems very readable and expressive. Or are you complaining about how t
by cliffy 10y ago
What is awful about:
foo = [transform(bar) for bar in baz.list() if condition(bar)] ?
Seems very readable and expressive. Or are you complaining about how they execute?
Also \ used judiciously with proper indentation can break statements over multiple lines without too much pain.
- djsumdog 10y agoYea, I like list comprehensions. I mean they make sense once you're use to reading the syntax. That's just like the following in Scala: foo = baz.list().filter{ bar => condition(bar) }.map(transform(_)).toList If it's your first time looking at Scala, you'd probably be like, "What the fuck is that shit?" but as you learn the language, these types of patterns become common and make a lot of sense. I mean it's not like weird rules in natural language. At least the grammars for computer languages are strict, with very few edge cases (compared to human/spoken language).
- p4lindromica 10y agoI hope you mean: foo = baz.list().filter(condition).map(transform).toList No need to create the extra anonymous functions.
- nerdponx 10y agoDoes Scala have line continuation? I got really used to pipes from R (which I guess come from F#/Elixir), which in turn got me really comfortable with multi-line statements like: foo = baz.\ list().\ filter{ bar => condition(bar) }.\ map(transform(_)).\ toList IMO this is about as readable as it gets. It's like bullet points enumerating each step in the "algorithm" that produces a `foo`. AFAIK Javascript also uses this pattern a lot.
- uiri 10y agoI think that Scala uses semicolon terminated lines so you would write something like: foo = baz .list() .filter{ bar => condition(bar) } .map(transform(_)) .toList;
- djsumdog 10y agoScala doesn't require the semi-colon at the very end, but it does allow for them if you really want two statements on the same line. Edit: and yes, that line separation works fine, both compiled and in the REPL.
- jfroma 10y agoBTW similar syntax in javascript, ruby, c#, etc.
- ezrast 10y ago1: When I hit the opening bracket, I don't know whether I'm looking at an array literal or a comprehension. I have to read ahead a few tokens to disambiguate. 2: When I hit `transform(bar)`, I don't know what `bar` is either. I have to jump forward to disambiguate again. 3: Once I hit `for bar in` I realize I'm in a comprehension, but that's still not enough to figure out what `transform(bar)` is acting on. I have to read to the end of the `if` condition, then backtrack to the beginning. bonus reason: why not `list(baz)`? Is there actually some logic to when Python uses methods and when it uses global functions? If so, please tell me. another bonus reason: when I was learning Python, I found the keyword reuse genuinely confusing. I would try to write for loops like `for x in my_list if condition(x):` and couldn't figure out why it didn't work because I knew I had seen that syntax somewhere before. Now, your particular example isn't that bad, but if you make it just a little more complicated you get something like this aberration: foo = [transform(bar) if bar.property else bar for bar in baz.list() if condition(bar)] Nothing will convince me that you're not a mutant if you think that's clear and concise. Meanwhile, over in Ruby-land, we write this: baz.each.select{ |bar| condition(bar) }.map{ |bar| bar.property ? transform(bar) : bar } Which to me parses very easily into meat-brain logic, in small chunks, with a single pass: -Start with `baz` -Consider each item -Select only those `bar`s that meet `condition` -Map each `bar` to... -`transform(bar)` when `property` is true; itself otherwise (okay, natural language actually more closely resembles Python-style ternaries here. Sue me). P.S. apologies for the multiple edits; I am an HN formatting noob.
- dragonwriter 10y ago> When I hit the opening bracket, I don't know whether I'm looking at an array literal or a comprehension. I have to read ahead a few tokens to disambiguate. All research I have seen says that proficient readers of a language read closer to a line at a time than a token at a time, so I suspect that not really a problem so much as a rationalization of aesthetic preference. > bonus reason: why not `list(baz)`? Is there actually some logic to when Python uses methods and when it uses global functions? list is a built-in type, and (as is usually the case for Python types) list() is the type constructor. There are other global functions in Python and there is room for debate over whether they make sense over methods, but constructors for built-types are pretty clear. baz.list() is a method on baz. Assuming baz is iterable, list(baz) is valid, it's just different than baz.list().
- zimzam 10y agoI generally like python's list comprehensions, but they have some ugly warts. For example, a simple comprehension looks like this: foo = [transform(bar) for bar in baz.list()] Adding an if condition looks like this: foo = [transform(bar) for bar in baz.list() if condition(bar)] But an if/else expression looks like this: foo = [if condition(bar) transform(bar) else other_transform(bar) for bar in baz.list()] Adding an else requires completely rewriting the line! Super ugly and inconsistent. Edit: formatting... don't know why my the 'list()' in my last example is disappearing
- marcstreeter 10y agomaybe it's bad form but I generally prefer to break my list/dictionary/set comprehensions into various lines. For me it increases the readability foo = [ if condition(bar) transform(bar) else other_transform(bar) # 1: storage for bar in base.list() # 2: iteration if bar_tester(bar). # 3: filtering ] to each his own I suppose, until the PEP8 police come and get us all!!!
- dragonwriter 10y agoFilters and ternaries aren't the same kind of thing (ternary if/else are analogous to SQL SELECT-clause case statements, filter if is analogous to SQL WHERE-clause; the positions in Python conditionals, which are very much like SQL SELECT statements, follows that analogy.)
- userbinator 10y agoInstead of asking "what is awful about X", how about considering "what would make it better"? I think this would be easier to read, given that what's inside the [] now looks almost exactly like the equivalent code without using a list comprehension: foo = [for bar in baz.list() if condition(bar) transform(bar)] (Disclaimer: I am not a regular Python user. Maybe that ordering conflicts with a syntax for something else.)
- dragonwriter 10y agoYou don't need line continuations to split comprehensions because the delimiters already allow you to split lines.