The Zen of Python

10 minute read comments

In my previous post, I shared some thoughts on the connections between Zen and the programming. I think, that these seemingly disparate fields share profound commonalities in their principles, such as simplicity, clarity, and mindfulness. In fact, this connection is not a subjective one at all. Python has built it directly into its programming, known as The Zen of Python.

gif “Snake”. Own drawing.

The Zen of Python

The Zen of Python”, developed by Tim Peters, is a collection of 19 aphorisms that serve as guiding principles for Python programmers worldwide. While not all of them might be self-explanatory or immediately applicable, they encourage developers to write cleaner, more efficient, and readable code, echoing the principles of Zen clarity, mindfulness, and simplicity.

As stated above, “The Zen of Python” is deeply integrated into Python and comes with Python’s base installation. The only thing it takes to reveal them, is to execute two lines of code:

import this
print(this)

Let’s take a closer look at each of these aphorisms and shed some light on their deeper meaning.

1. Beautiful is better than ugly.

This aphorism emphasizes the importance of creating aesthetically pleasing code. Beautiful code is clean, efficiently structured, and readable. It’s not just about functionality, but also about craftsmanship and pride in one’s work. Code is read more often than it is written, and making your code beautiful means making it easier for yourself and others to read and understand. Thus:

  • Beautiful code is clear, concise, and understandable.
  • Ugly code is cluttered, complicated, and difficult to read.
# beautiful:
result = [i for i in range(10) if i % 2 == 0]

# ugly:
result = []
for i in range(10):
    if i % 2 == 0:
        result.append(i)

2. Explicit is better than implicit.

In programming, being explicit means stating things directly and leaving as little as possible to inference or assumption. This principle advises against using overly complex constructs when a simpler, more explicit alternative is available. It results in code that’s more understandable, maintainable, and less prone to errors. Thus:

  • Explicit code states its intentions plainly.
  • Implicit code leaves you guessing what it does.
# explicit:
def calc_fraction(x, y):
  """Calculate the fraction of two input variables."""
  return x / y

# implicit:
def frac(**args):
  x, y = args
  return x/y

3. Simple is better than complex.

A powerful notion in both Zen and programming, this aphorism encourages programmers to create simple and straightforward solutions. It is always better to start with a simple solution and then introduce complexity only when it’s necessary. Remember, simple does not necessarily mean simplistic. It means that the solution is as straightforward as possible, given the problem at hand. Thus:

  • Simple code is straightforward and easy to understand.
  • Complex code has unnecessary intricacies and complications.
# simple:
def multiply(a, b):
    return a * b

# complex:
def multiply(a, b):
    result = 0
    for _ in range(b):
        result += a
    return result

4. Complex is better than complicated.

When simplicity isn’t enough to solve a problem, it’s acceptable to make the code more complex. However, it is essential to ensure that this complexity is a necessary part of the solution and not just a byproduct of poor code organization or design. The complexity should be inherent to the problem, not to the solution. Thus:

  • Complex code tackles a difficult problem with all its inherent difficulty.
  • Complicated code introduces difficulties that aren’t inherent in the problem being solved.
# complex:
def is_prime(x):
    """Return True if x is prime, False otherwise."""
    if x < 2:
        return False
    for i in range(2, x):
        if x % i == 0:
            return False
    return True

# complicated:
def is_prime(x):
    """Return True if x is prime, False otherwise."""
    return x > 1 and all(x % i != 0 for i in range(2, x))

5. Flat is better than nested.

Too much nesting can make code harder to read and understand. This guideline advises that it is often better to avoid deep nesting of code where possible. By keeping your code flat, you make it easier to read and reduce the chance of errors. Thus:

  • Flat code is easier to read because it has less indentation.
  • Nested code can become difficult to read with each level of indentation.
# flat:
if condition1:
    handle1()
if condition2:
    handle2()

# nested:
if condition1:
    handle1()
    if condition2:
        handle2()

6. Sparse is better than dense.

Writing code that is too dense, with too many operations happening in a single line or block, can make the code harder to read and understand. It’s better to spread out your code and use more lines if it makes your code easier to comprehend. Thus:

  • Sparse code is spread out and easy to read.
  • Dense code is compact and hard to read.
# sparse:
for i in range(10):
    print(i)

# dense:
print('\n'.join(map(str, range(10))))

or

# sparse and simple:
def get_integers_from_list(array):
    return [value for value in array if isinstance(value, int)]

def get_greater_than_zero_integers_from_list(array):
    return [value for value in array if value > 0]

def get_product_of_array_values(array):
    from functools import reduce
    import operator
    return reduce(operator.mul, array, 1)

def print_information(value):
    print(f"Product of positive numbers is {value}. Thank you.")

def print_product_of_positive_int_numbers_in_mixed_list(array):
    numbers = get_integers_from_list(array)
    positive = get_greater_than_zero_integers_from_list(numbers)
    product_of_values = get_product_of_array_values(positive)
    print_information(product_of_values)


# dense and complex:
def print_product_of_positive_int_numbers_in_mixed_list(array):
    numbers = [value for value in array if isinstance(value, int)]
    positive = [value for value in numbers if value > 0]
    product_of_values = 1
    for num in positive:
        product_of_values *= num
    print(f"Product of positive numbers is {product_of_values}. Thank you.")
    
# even denser:
def print_product_of_positive_int_numbers_in_mixed_list(array):
    from functools import reduce
    import operator
    print("Product of positive numbers is %s . Thank you." % 
          reduce(operator.mul, 
                 [value for value in 
                  [value for value in array if isinstance(value, int)] 
                  if value > 0], 1))

7. Readability counts.

This ties back to the first aphorism. Code is read more often than it is written. Prioritize making your code understandable to other humans, not just computers. Thus:

  • Readable code is self-explanatory.
  • Code that isn’t readable needs to be deciphered.
# readable:
def calculate_area(radius):
    return 3.14 * (radius ** 2)

# not readable:
def a(r):
    return 3.14 * (r ** 2)

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

In programming, consistency is key. This aphorism advises against writing special-case code that breaks established rules, as it can lead to bugs and make the code harder to understand and maintain. While it’s important to follow established best practices, sometimes real-world constraints require pragmatic solutions. In such cases, practicality takes precedence over theoretical purity. Thus:

  • We should try to follow established good practices when coding.
  • But sometimes we need to break the rules to solve a real-world problem.
# good practice (each function does one thing):
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

# breaking the rules (one function does multiple things):
def calculate(a, b, operation):
    if operation == 'add':
        return a + b
    elif operation == 'subtract':
        return a - b

or

# a purist approach for filtering out odd numbers from a list:
def filter_odd_numbers_purist(numbers):
    return [number for number in numbers if number % 2 == 0]

# a more practical approach:
def filter_odd_numbers_practical(numbers):
    if not numbers:
        return []
    else:
        return [number for number in numbers if number % 2 == 0]

or

# multiple statements per line:
x = 1; y = 2; z = 3

if x == 1: print('x is 1'); print('x is still 1')

# one statement per line:
x = 1
y = 2
z = 3

if x == 1:
    print('x is 1')
    print('x is still 1')

10. + 11. Errors should never pass silently. Unless explicitly silenced.

Errors are your friends. They help you understand what went wrong, so don’t ignore them. Make sure your code handles errors and does something meaningful with them. There may be times where you purposely want to ignore an error. If so, make sure it’s a conscious decision and clearly indicated in your code. Thus:

  • Code should notify us when something goes wrong.
  • Unless we are sure we want to ignore an error.
# errors should not pass silently:
try:
    x = 1 / 0
except ZeroDivisionError:
    print("You tried to divide by zero!")

# unless explicitly silenced:
try:
    x = 1 / 0
except ZeroDivisionError:
    pass  # We know division by zero is not allowed, but we don't want the program to stop or complain

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

Ambiguity in code can lead to bugs and unexpected behavior. If something isn’t clear, don’t guess. Take the time to understand what the code is doing. Thus:

  • Code should be clear and not open to interpretation.
  • Ambiguous code can lead to mistakes and errors.
# ambiguous:
def calculate(num1, num2):
    return num1 * num2  # Is this supposed to multiply? Or was it supposed to add/subtract/divide?

# Clear:
def multiply(num1, num2):
    return num1 * num2

13. + 14. 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.

This aphorism advises against creating multiple solutions to the same problem in your code. Having a single, clear way of doing things improves code readability and maintainability. The second aphorism is a humorous nod to Python’s creator, Guido van Rossum, who is Dutch. Sometimes the best solution may not be immediately apparent and might require some thought. Thus:

  • Python tends to have one clear way to accomplish a task.
  • There may be other ways, but the clearest should be chosen.
# obvious way:
for i in range(10):
    print(i)

# not the obvious way:
i = 0
while i < 10:
    print(i)
    i += 1

15. + 16. Now is better than never. Although never is often better than right now.

Starting now is usually better than never starting at all. Even if your initial solution isn’t perfect, it’s better to start coding and then refine your solution over time. However, while it’s important to start, you also don’t want to rush into coding without proper planning. Spend some time designing your solution before starting to code. Thus:

  • It’s good to start coding now rather than never starting at all.
  • But sometimes, it’s better to take a moment to plan rather than rushing in.

17. +18. 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.

Code often needs to be understood by other developers. If you can’t easily explain how your code works, it might be too complicated and could probably be simplified. Conversely, if you can easily explain your solution, it’s probably a good one. This underlines the importance of communication and clarity in coding. Thus:

  • Good code is easy to explain because it follows a clear logic.
  • Code that’s hard to explain usually has convoluted logic and is best avoided.

19. Namespaces are one honking great idea - let’s do more of those!

Namespaces help prevent naming conflicts in your code, making it easier to organize and understand. They’re a powerful tool, and using them effectively can make your code much better. Thus:

  • Namespaces keep our code organized and prevent naming conflicts.
# good use of namespaces:
import numpy as np
import matplotlib.pyplot as plt

# without namespaces:
from numpy import *
from matplotlib.pyplot import *

Summary

Remember, these are not strict rules but rather guiding principles. There can be exceptions based on the specific problem you are trying to solve. The Zen of Python is about making code more accessible and easier to read, leading to better software development.

Conclusion

The Zen of Python serves as a valuable compass guiding Python programmers towards more mindful and effective programming practices. By internalizing these aphorisms, we can create code that is not only functional but also elegant, understandable, and maintainable. Just as Zen teaches us to live in the present moment and appreciate the beauty in simplicity, so too does the Zen of Python guide us to become more conscious and thoughtful coders.


Comments

Comment on this post by publicly replying to this Mastodon post using a Mastodon or other ActivityPub/Fediverse account.

Comments on this website are based on a Mastodon-powered comment system. Learn more about it here.

There are no known comments, yet. Be the first to write a reply.