Getting in the Python Mindset

Early in my Python career, I discovered import this. It’s an easter egg of sorts. Here’s the output:

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

It’s not like these concepts are Python-specific. Readability is important, regardless of language choice. Flat is better than nested, again, regardless of language choice; and so on, and so forth. What I love about Python—and I think it’s a community thing—is that people really take this to heart. I don’t believe C++ coders don’t strive for this, but they don’t have a word for it. Pythonists call it the Pythonic way.

It’s a strange concept for a beginner Python coder to understand, more so if said hacker has a background in a more traditional language—say, C++. Experienced coders often say there is only one right way to do something in Python, and that is the Pythonic way. It’s a mindset that isn’t easy to get into; I had trouble myself. I wasn’t writing bad code per say—it did what I wanted to, and often times, was more than speedy enough. It was just—looking back now—cumbersome, verbose and non-idiomatic. There’s obviously a lot of argument to what is the one, right Pythonic way at higher levels, but here’s a few examples.

A C++ coder would apply a function to every element in a list like this:

for (int i = 0; i < spam_length; i++) {
  eggs(spam[i])
}

It’s relatively clean; the syntactic structure of the for loop in C++ is short and doesn’t require much cruft. An inexperienced Python programmer might try to implement the exact same thing like this:

i = 0
while i < spam_length:
  eggs(spam[i])
  i += 1

It almost hurts me to look at that! I would hope that anyone who has been hacking around in Python for even a few weeks would see how many issues there are with that code. Luckily, even a mediocre tutorial or teacher would teach a beginner that there are better ways to do that. The next stage could possibly be:

for i in range(len(spam)):
  eggs(spam[i])

This is a big improvement. It eliminates the redundant i as a counter and iterates over a generated list of integers. A step in the right direction, but this still isn’t Pythonic. Lists (and tuples and dictionaries) and how they are handled are extremely tightly ingrained into how you write code in Python. I haven’t yet encountered a language where there is such a reliance on data structures as almost a part of syntax. The following highlights this well:

for element in spam:
  eggs(element)

That’s it: short and sweet. I should mention I’d never take this approach—I don’t like modifying lists in-place. I would use a list comprehension and generate a new list:

[eggs(element) for element in spam]

Discovering list comprehensions changed everything. So elegant, so clean, yet incredibly powerful if you employ inline if statements or use lambda expressions. You could do it with map and a lambda expression, but map (as well as other functions that I consider to be fairly useful) are being deprecated changed to return iterators with the next generation of Python, so I guess they aren’t really Pythonic! There’s so much more that I haven’t covered and hope to sometime in the future: generators, decorators, closures, etc., and while it sounds like this post is a gushing fanboy’s proclamation against C++, Python borrows heavily from other languages. Taking great features from various languages and putting them into one is a good thing1.

If you see or write a really awesome piece of Python code, I’d love to see it; maybe a nifty little Pythonic twist on a traditional method of getting something done. Go.

Update: It’s been brought to my attention that I actually presented the idiomatic C way, rather than C++ (thanks @scott_s).

Update 2: There’s a (very minor) debate going on over at News.YC as to whether for_each actually is or isn’t the idiomatic C++ way. If you think you know, please let me know.

  1. Python’s decorator syntax is from Java; list comprehensions are from SETL/Haskell

—★—

« Google App Engine | So I’m a Software Pirate? »