I'd agree if you'd said "not a lot of key/values," as the setup could supersede the subsequent speedups. However, in that case, the difference is negligible, and we should do what is "pythonic."
I think you might have glossed over another very useful "shortcut" not covered in this article, the use of multiple assignments in a single statement.:
Nice list. I only wish the author warned the readers that using the "get" method to get an item from the dictionary is not 100% equivalent to using try/except.
When using the method, the default value argument will always be evaluated, regardless of whether the dictionary key exists. If the expression that produces the default value is an expensive one or has side effects, the programmer might want to use the try/except variant instead.
If you use print() in py2k, you're still using the print statement and group the argument in parentheses. It falls apart, if you try to use more than one argument, because it's interpreted as a tuple then.
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.
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.
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:
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.
Great post! For those who know Python, this may be common knowledge, but for the uninitiated, this is a great showcase of some simple ways that Python makes coding more intuitive and enjoyable.
You might also consider mentioning both dictionary and set comprehensions along with list comprehensions, as they are the exact same concept, yet even a lot of intermediate Python programmers don't know about them!
Too bad there was no source control in the company then, so I could not find out who was responsible for that travesty and "talk calmly" some sense into them.
Processes (and a common design for c functions) return zero on success and an error code otherwise. Although it might be unexpected (and certainly breaks flow constructs), it's probably not so bad with some context.
Worse, though, Windows defines TRUE and FALSE for you somewhere in windef.h - so you would have to be careful about where your code was included..
Shouldn't "the last 3" be [-3:] instead of [3:] ? Inyour case it gives the correct result, but that's because your list has 6 elements i think. ( note : typing on my phone so i can't verify).
"fizz"[0] is the zeroth character in the list / string
Note "fizz"[:] will output all chars in the string (implicitly it's [0:] - from zeroth string to end
X % 3 is x modulo 3, producing 0 only if x is divisible by
three - so we want to print fizz here. 4 is the number of chars in both fizz and buzz - so the meat is
"fizz"[x%3*4:] is "fizz"[0:] if x%3 is 0 - when we want tp print fizz, otherwise it's [somevaluegreaterthan4: to the end of the list (ie nothing). The extra : stops index error
Now I understand it. I wasn't aware one could append a subscript operator after a litteral string. I also didn't know of the second : role. Thank you.
But what do you get if x is 0 ? As I now uneerstand it, you would get "fizzbuzz". Shouldn't the list start at value 1 ? So shouldn't the range be (1, 101) instead of (101) ?
You're correct. That was my mistake. Here's the updated version:
for x in range(1,101):print"Fizz"[x%34:]+"Buzz"[x%54:]or x
I basically just removed the extra colons and added 1, to the range so that it starts at 1. lifeisstillgood was spot on with the reasoning that this works.
It prints a substring from "Fizz" using slicing.
The thing is, the x%3*4 determines the start of that slice. It's either 0, which is when X modulo 3 == 0 (which is every third number in range(101) ), or something larger than 4, in which case the slice would start at the end of "Fizz" thus yielding an empty string.
nice list, agree with the other comments that the Fizzbuzz example is cool, but can be confusing to work out what it does, especially since this post is aimed at beginners.
I would also mention `getattr` similarly to `get`.
The article requires some corrections if presented to beginners.
`something` should be written as repr(something). `` (backticks) are gone in Python 3.
if 0 < x > 1: is syntactically correct but it should be written as: if x > 1. The combining syntax could be used for the same direction e.g., if -1 < x < 1.
Code golf is not the strong side of Python and it is not the point of FizzBuzz. Code golf might demonstrate language features but it doesn't provide the correct context for their usage i.e., code golf doesn't show to a beginner how something should be used correctly.
True/False are keywords Python 3 (you can't assign to them).