Geekflare is supported by our audience. We may earn affiliate commissions from buying links on this site.
In Development Last updated: July 4, 2023
Share on:
Invicti Web Application Security Scanner – the only solution that delivers automatic verification of vulnerabilities with Proof-Based Scanning™.

Want to get better at writing Python code? Here’s how the Zen of Python can help you take the first steps towards it.

Python is super simple to learn. But writing idiomatic and Pythonic code that’s easy to maintain can be challenging—especially for beginner programmers. PEP-20 introduced “The Zen of Python”, a poem by Tim Peters, that outlines the importance of writing Pythonic code that adheres to best practices.

To read the Zen of Python, you can start a Python REPL and run:

>>> import this
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!

As seen, most of the aphorisms in the Zen of Python are self-explanatory. Some aphorisms should be coupled with the next when interpreting, while some others contradict an earlier aphorism. Nonetheless, the Zen of Python is a fun, engaging, and practical read!

Interpreting the Zen of Python

zen-of-python-2

The Zen of Python was proposed to have 20 guiding principles for programming in Python. However, there are only 19 aphorisms thus far. Let’s go over them.

Beautiful is better than ugly.

This aphorism emphasizes the importance of writing elegant and Pythonic code.

The following code snippet has a code smell:

def square(num):
    squares = []
    for i in range(num):
        squares.append(i*i)
    return squares

The function: 

  • Initializes an empty list 
  • Has a loop inside the function that appends elements to the end of the list and 
  • Finally returns a list 

While this is functionally correct—it’s not Pythonic—and is hard to maintain.

You can write it much more elegantly using generators. Here’s the generator function equivalent of the above function:

def square(num):
    for i in range(num):
        yield i*i

Or even better, you can have the following generator comprehension expression:

num = ...
squares = (i*i for i in range(num))

Explicit is better than implicit.

When writing code do not leave other developers and users guessing the implied or default behavior of the code. Be explicit. Take the example of wildcard imports:

from some_module import * # wildcard import
from some_other_module import *

result = some_function() # where did this come from?

Avoid using wildcard imports as much as possible. Because it is not explicit and inefficient. Be specific when importing functions and classes from other modules:

from some_module import this_function # explicit import

result = this_function() # we now know.

Simple is better than complex.

This aphorism states that we should keep the code simple and avoid needless complexity. For example: you may want to reverse a string, and you implement of following recursive solution:

def reverse_string(my_string):
  if my_string == "":
    return my_string
  else:
    return reverse_string(my_string[1:]) + my_string[:1]

Though this works, this is likely an over-engineered solution to this problem—given that there are simpler and more Pythonic ways to do it.

Here’s the string-slicing approach:

>>> rev_string = my_string[::-1]
>>> rev_string
'nohtyP'

And here’s the approach using built-in methods and functions:

>>> rev_string = ''.join(reversed(my_string))
>>> rev_string
'nohtyP'

Complex is better than complicated.

So what does this next aphorism in the Zen of Python convey? 

String reversal in Python is a super simple operation. In practice, though, we may need more complex logic. Here’s a fairly simple example:

Say you need to connect to a database:

  • You should first parse a toml config file—to retrieve the configuration information of the database.
  • The database connector should be installed. 
  • You can then define a function to connect to the database, anticipate connection errors, implement error handling, and much more.
  • Finally, after connecting to the database, you can query it.

Though this is still simple enough, it needs more complex logic as compared to string reversal. But that doesn’t mean it has to be complicated. You can still use the functionality of built-in modules code effectively and organize your code so that other developers can read, understand, and contribute to it.

Flat is better than nested.

A flat structure is easy to parse and understand than a nested structure. As you work on a project, you might be tempted to isolate functionality by creating separate modules. However, too much granularity can be excessive.

That said, you may often need to go beyond the flat structure. But even if you need nesting, keep it to a minimum.

Here is an example:

from db_info.config.actions.parse.parse_config import parse_toml # too difficult to parse!
...

from db_config.parse_config import parse_toml # much better!
...

Sparse is better than dense.

If you are just starting out in your developer journey, you might be tempted to overuse some of the features of the language. List comprehensions, for instance, are Pythonic—but only when you use them where they are needed.

Look at the following comprehension:

prices_dict = {'melons':40,'apples':70,'berries':55}
items = [(fruit,price) for fruit in prices_dict.keys() if fruit.startswith('m') for price in prices_dict.values() if price < 50]
print(items)
# Output: [('melons', 40)]

The list comprehension is too dense and difficult to parse. In this case, using a for loop equivalent with conditionals will be more readable. Meaning the comprehension is difficult to comprehend. 🙂

Readability counts.

You should always write readable code. Here are a few simple ways to improve code readability:

  • Using descriptive variable names
  • Adding docstrings for functions and classes
  • Commenting code where needed
  • Adding type hints for arguments and return types of functions

Special cases aren’t special enough to break the rules.

You should—as much as possible—adhere to the rules of the language and the recommended best practices.

But is this always possible? No, and that’s why we have the next aphorism.

Although practicality beats purity.

This is a continuation of the previous aphorism. Though it’s recommended to follow the rules of the language, in certain cases, it’s perfectly fine not to follow some of the principles.

Errors should never pass silently.

In Python runtime errors are quite common. As a good practice, you should always handle errors and not silence them as a quick fix.

You can anticipate and implement appropriate error handling—for the different error types:

try:  
    # doing this
except ErrorType1:
    # do something
except ErrorType2:
    # do something else
...

You should avoid bare and generic exceptions. Newer versions of Python (since Python 3.11) support exception chaining and exception groups to perform more sophisticated exception handling.

Unless explicitly silenced.

This follows the previous aphorism. If the design requires or allows for the error to be silenced, then it should be done explicitly.

For example: when connecting to the database, you may run into OperationalError due to invalid config information. Try connecting using custom config. In case there is an OperationalError, use the default config and try to connect to the database.

try:
   # connecting using custom config
except OperationalError:
   # connect using default config

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

This aphorism in the Zen of Python is self-explanatory. When in doubt, do not guess. But run the code and check the output. Then depending on whether you have the desired behavior, improve readability or modify the logic as needed.

Take the following simple example with a tuple of Booleans:

>>> True, True == (True, True)
(True, False)
>>> True, (True == (True, True))
(True, False)
>>> (True, True) == (True, True)
True

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

To accomplish a certain task, there should be one and only one recommended pythonic way to do it. However, for any problem, we can have multiple solutions.

Even in the simple string reversal example, we looked at a recursive solution, string slicing, and the join() method.

This is also an inside joke given the inconsistent use of em-dashes. We generally use em-dashes without leading and trailing spaces. Or we use it with both the leading and trailing spaces.

So here’s what we can infer. The aphorism that emphasizes that there should be one—and only one—Pythonic way to do things can itself be written in more than two ways.

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

Written on a light note, this refers to Guido Van Rossum, the creator of Python (who is Dutch). The (most) Pythonic way to accomplish a particular task—comes naturally only for the creators of Python.

So for developers, it requires experience—and learning from experience—to get better at tapping into the features of the language.

Now is better than never.

As with a few other aphorisms in the Zen of Python, this one can be interpreted in a couple of different ways, too.

One interpretation is that, as a developer, it’s quite common to procrastinate to start coding a project. Rather than waiting to plan out the finest details of the project, starting now is a better idea.

Another possible interpretation is: code that runs in a finite number of steps—and terminates—is often better than code that is buggy and gets stuck in an infinite loop. 

Although never is often better than right now.

This aphorism seems to contradict the previous one. Though it is better not to procrastinate, we should still think through the problem and design the code accordingly.

Coding a module—without giving it proper thought—ridden with code smells and anti-patterns is a bad idea. Because such code is difficult to refactor and implement corrective measures.

If the implementation is hard to explain, it’s a bad idea.

zen-of-python-1

Any logic—however complex it may be—can always be implemented in a form that is simple to explain and easy to understand.

If the implementation is difficult to explain, there’s probably some needless complexity. The code can be modified or refactored so that it is easier to follow along.

If the implementation is easy to explain, it may be a good idea.

This is related to the previous aphorism and is self-explanatory, too. If the implementation can be explained in simple terms, then it is likely a good idea.

Because such code whose implementation can be described—in simple terms—is very likely to be readable and easy to follow—with minimal complexity.

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

In Python, objects in a specific scope can be accessed using their names in their namespace. For example you can create a class and use it as a template to create instances of the class. Now the instance variables will all be in the namespace of the instance.

This allows us to use objects with the same name—without conflicts—as they are in different namespaces. However, you should only use them as required and ensure that the simplicity and readability of the code are not compromised.

Conclusion

That’s all for this tutorial! I hope this guide helped you understand how the Zen of Python emphasizes code style and good coding practices in Python. The more you code, the better you will get at it.

If you are interested in learning how to write concise and readable code, read this article on Python one-liners.

  • Bala Priya C
    Author
    Bala Priya is a developer and technical writer from India with over three years of experience in the technical content writing space. She shares her learning with the developer community by authoring tech tutorials, how-to guides, and more…. read more
  • Narendra Mohan Mittal
    Editor

    Narendra Mohan Mittal is a Senior Digital Branding Strategist and Content Editor with over 12 years of versatile experience. He holds an M-Tech (Gold Medalist) and B-Tech (Gold Medalist) in Computer Science & Engineering.


    read more
Thanks to our Sponsors
More great readings on Development
Power Your Business
Some of the tools and services to help your business grow.
  • Invicti uses the Proof-Based Scanning™ to automatically verify the identified vulnerabilities and generate actionable results within just hours.
    Try Invicti
  • Web scraping, residential proxy, proxy manager, web unlocker, search engine crawler, and all you need to collect web data.
    Try Brightdata
  • Monday.com is an all-in-one work OS to help you manage projects, tasks, work, sales, CRM, operations, workflows, and more.
    Try Monday
  • Intruder is an online vulnerability scanner that finds cyber security weaknesses in your infrastructure, to avoid costly data breaches.
    Try Intruder