Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I actually would prefer people on my team NOT use these shortcuts. For example:

  numbers = [1, 2, 3, 4, 5, 6]
  even = []
  for number in numbers:
      if number % 2 == 0:
          even.append(number)
is much easier to read and maintain imho then

  numbers = [1, 2, 3, 4, 5, 6]
  even = [number for number in numbers if number % 2 == 0]
Also:

  for x in range(1,101):print"Fizz"[x%3*4:]+"Buzz"[x%5*4:]or x
is a piece of code I never want someone else to write that I may someday have to maintain. Write it out the long way and make your teams lives easier.


While it's OK for you to enforce not using trivial list-comprehensions on your team, I think you'll find the majority of Python's community disagreeing. Your example is really tame as far as comprehensions are concerned, and "beginners" are going to need these basics to comprehend more advanced patterns.


It's especially tame given the friendly variable name chosen.


There is a fundamental difference between the loop and the comprehension: the latter is far more declarative.

That is, the comprehension is equivalent to saying something like "even contains every number from numbers that is even". The loop is like saying "start with even as the empty list; for each number in numbers, append it to even". It's much easier to understand what even is from the first description.

The for-loop version is much less direct and has too many low-level details--why are you appending to the list and using extra state? From the second definition, you can know what even is just by looking at it; for the first one, you have to think about what the code is doing.

This is the fundamental delineation between imperative and declarative code. The former is about how and the latter is about what. In general, specifying the what is much simpler--and therefore easier to write, easier to work with and easier to maintain--than specifying how to get it.

I suspect you find the for-loop version easier not because it's simpler but because that's what you're used to. And while familiarity is certainly an important factor, it's always relative and temporary: every person is familiar with different things, and you get more familiar with different constructs over time.

Rich Hickey's "Simple Made Easy"[1] talk is a great description of this whole idea. He makes the matter far clearer than I have any hope of doing.

[1]: http://www.infoq.com/presentations/Simple-Made-Easy


There is a fundamental difference between the loop and the comprehension: the latter is far more declarative.

I completely agree with this, and the wider fundamental point throughout your post.

However, I’m not a fan of comprehension syntax. It often gets noisy even for trivial cases like this one: the letters “number” appear four times in just a single line here, which as it turns out is just as much accidental complexity as using the explicit loop control variable in the imperative version and you’ve lost the visual cues to what each means that the indentation gives with the loop. For more complicated transformations, I find comprehension syntax also scales poorly.

I suspect (though I’ve no hard data to back it up) that comprehension syntax actually isn’t very readable in many cases, and that this may be why some people prefer the kind of code in the imperative example rather than any innate preference for imperative style per se. Personally, I’d prefer to highlight the data flow but using more explicit transformations instead, such as (in a hypothetical functional programming syntax):

    evens = filter {_ % 2 == 0} numbers
Python’s own syntax for this isn’t quite as neat as some functional programming languages, IMHO, but I still prefer it to the comprehension:

    numbers = [1, 2, 3, 4, 5, 6]
    evens = filter(lambda n: n % 2 == 0, numbers)


To be fair, we should be comparing like tokens, if the proof is using them as part of its advantage:

  evens = filter(lambda n: n % 2 == 0, numbers)
with

  evens = [n for n in numbers if n % 2 == 0]
or

  evens = [n for n in numbers if not n % 2]
Choosing token names is certainly a different


Fair comment. I suppose that’s why a more declarative style tends to work much better in a language designed for it. For example, functional programming languages tend to have neat syntactic sugar for things like simple lambda expressions or applying a series of transformations like the filter here, without introducing accidental complexity like extra identifiers that the reader than has to keep track of. The moment you’ve added that kind of baggage, which is almost inevitable to some degree in a language like Python, the clarity tends to suffer.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: