Contemplating the Zen of Python

A brief analysis of the 19 guiding principles for Python design

Chaitanya Baweja
Jan 6 · 7 min read
Image for post
Image for post

While reading an article last week about the PEP8 Style Guide for Python, I once again came across the Zen of Python. For those who haven’t seen it before, you can easily conjure it by casting this spell in your Python interpreter:

import this

Long-time Pythoneer Tim Peters penned down the BDFL’s [Benevolent Dictator For Life, a nickname of Python creator Guido van Rossum] guiding principles for Python’s design into 20 aphorisms. This poem has served as a mini style-guide for Python coders for over a decade.

Mysteriously, only 19 of the guidelines are written down. Guido van Rosum reportedly said that the missing 20th aphorism is “some bizarre Tim Peters in-joke.”

This article contains my interpretation of these aphorisms, including examples and applications.


Beautiful is better than ugly.

Being a data scientist, more often than not, I write code that simply works. I might care about time and space efficiency, but rarely about readability. I do often regret this habit whenever I have to look back at a script I wrote earlier.

While it is not mandatory for code to be “beautiful”, Python as a language has been designed to keep consistency, readability, and simplicity in mind. For example, using or, and vs || , && :

if (is_valid(a) && b == 0 || s == 'yes') {vsif is_valid(a) and b == 0 or s == 'yes':

Python succeeds at being precise, concise, explicit and elegant at the same time.


Explicit is better than implicit.

It is very important for your code to be verbose and explicit. Here is an example:

Question: Which sin is being committed here?

It’s best to name a module explicitly every time you invoke it. For example, doing this would have made the life of Karan (a new addition to my company who is working with my code) much easier.

Now, it’s very clear which sin is being committed.

Image for post
Image for post

Similarly, implicit operations like this are not allowed in Python.

Image for post
Image for post

You must use explicit typecasting.

The entire concept revolves around the philosophy: don’t make me think.


Simple is better than complex. Complex is better than complicated.

A simple solution is always better than a complex one. A good example of this is reversing a string in Python. The fastest and most elegant way to do this would be using a one-liner slicing operation.

my_string = "ABCD"
reversed_string = my_string[::-1]

But, if I love painfully pointless solutions, I might choose recursion for the same problem:

It must be noted, though, that we should not complicate our solutions by looking for simpler elements. For example, adding two arrays without using numpy:

Adding two arrays with using numpy:

Prefer simplicity to complexity, but know the limits of simplicity.


Flat is better than nested.

Programmers typically love to organize their code into modules that contain sub-modules which contain other sub-sub-modules. This hierarchical structure often adds confusion rather than organization.

If you need to import functionality into your module, like import foo.bar.i.am.function then you need to stop.

Prefer shallow, rather than deep, nesting.


Sparse is better than dense.

I know single-line codes are a great way to impress your buddies, but they will infuriate your co-workers who have to spend hours understanding it. Imagine coming to work on a Monday morning and the first line of code that you see is this.

print('\n'.join("%i  bytes = %i bits which has %i possible values." % (j, j*8, 256**j-1) for  j in (1 << i for i in range(8)))) 

Code that is spread out over multiple lines is often easier to read than dense one-liners.


Readability counts.

Let’s comparing printing hello world in C and python.

vs.

Code is read more often than it’s written. Heroes don’t write overly terse code. They are explicit with the variable names and document everything.

Well-indented code is more readable. Thus, in Python it’s mandatory.


Special cases aren’t special enough to break the rules. Although practicality beats purity.

While these two aphorisms might seem contradictory, I feel that they complement each other very well. Programming is filled with “best practices” and styling guides.

While it is best to stick to these guidelines in software development, you might be tempted to evade these for quick hacks and, before you know it, you are surrounded with undocumented terribly inefficient legacy code.

But, keep practicality in mind. It doesn’t make sense to force object orientation principles where a simple script might do.


Errors should never pass silently. Unless explicitly silenced.

Image for post
Image for post

Silent errors happen when functions return None or error codes rather than raising an exception. This aphorism states that its better for a program to crash than to silence the error and continue running.

Avoiding errors would eventually lead to bugs that are harder to debug as they are far removed from their original cause. It’s best to make these errors explicit.

In cases when you wish to ignore an error that your code might cause, it’s best to make it explicit.


In the face of ambiguity, refuse the temptation to guess.

This reiterates the idea of making your code elegant, readable and explicit. Consider the following code:

What would be printed on the screen?

You might argue that a professional programmer would be well aware of the precedence of operators in Python. But, the question is, “Can this ambiguity be avoided?”

Trying stack overflow solutions until things work won’t help in the long run.

Debugging requires critical thinking. There is a good possibility that you might simply be masking the problem rather than completely solving it.


There should be one — and preferably only one — obvious way to do it.

This belief is throwing shade on the Perl programming language’s motto, “There’s more than one way to do it!”. While having multiple solutions for the same problem adds flexibility, it requires you to put in the extra effort of getting familiar with all the solutions.

P.S. There is an inside joke here that most people miss: the postfix operator after one and the prefix operator before obvious in the aphorism.

New programmers often get confused between whether to use postfix or prefix operator in a particular situation. Python solves this confusion by not supporting them altogether.


Although that way may not be obvious at first unless you’re Dutch.

This aphorism refers to the creator of Python, Guido van Rossum, who is Dutch. A common example used to denote his genius is C’s hotly debated ternary operator.

a = condition?expression1:expression2;

In Python,

a = expression1 if condition else expression2

However, not even this aphorism prevented Python from incorporating three different ways of formatting strings.


Now is better than never. Although never is often better than *right* now.

Code that hangs or gets caught in infinite loops is obviously worse than code that doesn’t. However, it’s almost certainly better to wait for your program to finish than to have it finish too early with incorrect results.

These aphorisms also work for your programming projects. It’s best to start today, rather than procrastinating endlessly. But a project never undertaken might still be better than a hastily executed one.


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.

Python is a programmer’s language, designed for readability and ease of maintenance. Python thrives for simplicity and elegance in design. If your “high-performance” code is impossible for your fellow co-workers to understand, it’s bad code.

But, having lucid code doesn’t necessarily mean that it still isn’t bad code. Programming is hard.


Namespaces are one honking great idea — let’s do more of those!

Namespaces are a collection of names. Different namespaces can co-exist at a given time but are completely isolated. These create a system in Python that prevent names in one module from conflicting with names in another.

But also remember that flat is better than nested: namespaces should only be used to prevent naming conflicts, not to force unnecessary categorization.


Conclusion

Python is a no-bullshit programming language designed to keep simplicity and readability in mind. There is merit in keeping these guidelines in mind while writing your code.

In the end, these guidelines are opinions that can be argued for or against. As we saw in this article, many of the principles seem to contradict each other. Unless you’re writing a book full of programming best practices, arguing over how code should be written is seldom fruitful.

The underlying philosophy remains: “practicality beats purity.”


Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store