Every programming language has some guiding principles. With PEP (Python Enhancement Proposals), developers and computer scientists often suggest changes and principles for the Python programming language. One such collection of guiding principles is the Zen of Python. This article discusses the zen of Python with examples to help you understand how to write better code in Python.
What is The Zen of Python?
The Zen of Python is a collection of 20 guidelines or heuristics suggested by Tim Peters. The statements in the zen of Python are as follows.
- 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!
You can obtain all the statements in the zen of Python by executing the command “import this” in the Python terminal or IDLE as shown below.
Now, we will discuss each statement in the zen of Python with examples to understand them in a better manner.
Beautiful is Better Than Ugly
This heuristic in the zen of Python says that we should always write clean and readable code. We can always write and execute an ugly but working code without focusing on readability. However, introducing readability and beauty to the code is always better as messy code is hard to understand. For instance, consider the following example.
x=10
y=20
z= x+y if x < y else x-y
print(z)
In the above code, we have used the assignment and comparison operations in a single statement. It makes the code less readable. Instead, we can use the following code to implement the same logic.
x=10
y=20
if x<y:
z=x+y
else:
z=x-y
print(z)
You can observe that the above code is far more understandable than the previous code. Hence, we should always focus on the readability of the code.
Explicit is Better Than Implicit
While writing code, we should always make the code more verbose and explicit. The code should be readable and easy to understand for anyone who reads it. We should always explain the expected behavior of the code and not rely on hidden or implied behavior. To understand this, let us write a function to add two numbers.
def add(a, b):
return a + b
In the above code, we can pass a variable of any data type to the function. In such a case, the function can show undesired behavior or it can also raise exceptions. For example, if we pass a string and an integer as input to the function, the program will run into an error.
To solve this confusion, we can write the above code in the following manner.
def add(a: int, b: int) -> int:
return a + b
In this example, the add() function is defined with explicit data types for the arguments and return value using type hints. The return value is also explicitly annotated with the int data type. This makes the code more clear and easier to understand, especially when the code is read by other developers.
Simple is Better Than Complex. Complex is Better Than Complicated.
The principle “simple is better than complex” in the zen of Python states that if we can solve a problem with a simple code, we should never try to implement the same functionality with a complex code.
If we get a simple problem, we should always use a simple solution. If we get a complex problem, we should try to break it down into simpler problems and implement it. To understand this, let us write a simple code to reverse a string.
def reverse(myStr):
if myStr:
return reverse(myStr[1:])+myStr[0]
else:
return myStr
In the above code, we have used recursion to reverse a string. Here, instead of using recursion, we can use the indexing operator to reverse the string in a single statement as shown below.
myStr[::-1]
This implementation is very simple compared to the recursion approach. Writing simple code will also reduce errors.
The statement “complex is better than complicated” is an extension of the statement “simple is better than complex”. It says that if we have a complex problem that cannot be solved in a simple manner, we can choose a complex solution.
However, the solution should be implemented with readable and understandable code modules. We can create functions and modules with high cohesion and low coupling to implement each step of the solution. Then, we can combine all the code to produce the output for a complex problem.
Flat is Better Than Nested
This statement suggests we should not create modules and sub-modules for each functionality. Hierarchies in a code are bad. In a similar manner, we should not use code with many nesting levels using for loops and while loops. Always try to write a flat code with minimum nesting levels.
Sparse is Better Than Dense
The statement “Sparse is better than dense” in the zen of Python suggests that we should not try to perform many operations in a single statement. Writing dense code can give us the correct output but it reduces the readability of the code. Hence, we should always break the code into parts and write easy-to-follow statements instead of dense one-liner code. To understand this, consider the following example.
Numbers=[1,2,3,4,5,6,7,8,9,10]
evenSquares=[number**2 for number in Numbers if number%2==0]
The above code creates a list of squares of even numbers from a given input list “Numbers”. Here, you can observe that we have created the output list using list comprehension with conditional statements. Although this code produces the desired output, it can be hard to understand for a beginner who wants to learn Python.
Instead, we can use the for loop with an if statement to implement the same logic as shown below.
Numbers=[1,2,3,4,5,6,7,8,9,10]
evenSquares=[]
for number in Numbers:
if number%2==0:
square=number**2
evenSquares.append(square)
In this code, each statement does a single task and the code can be understood easily by anyone.
Readability Counts
This statement in the zen of Python is self-explanatory. We write code only once. However, many programmers read the code multiple times over a time period. Hence, we should always write readable code. We must invest time in writing code and we must not abbreviate function and variable names. We should always use comments and self-explanatory names to make the code more readable and understandable. To understand this, let us rewrite the code used in the previous example with random variable names as shown below.
x=[1,2,3,4,5,6,7,8,9,10]
y=[]
for i in x:
if i%2==0:
j=i**2
y.append(j)
The above code will produce the same output as the previous code. However, it is very hard to explain what the code does by simply reading it. Hence, we should use proper variable names and comments while writing code.
Special Cases Aren’t Special Enough to Break The Rules. Although Practicality Beats Purity.
The statement “Special cases aren’t special enough to break the rules” in the zen of Python suggests we should always follow programming practices to write code. We shouldn’t use tools that violate the basic principles of a programming language. Writing code shouldn’t only focus on getting things done.
The statement “Although practicality beats purity” suggests that we can break the rules sometimes for practical reasons. We can deviate from established coding practices in Python if we can solve a problem easily using any approach.
Errors Should Never Pass Silently. Unless explicitly Silenced.
The above statement suggests that we should always avoid silent errors in a code. For example, consider the following code.
def divide(a,b):
try:
return a/b
except:
pass
In the above code, the function divide() returns None when a zero division error occurs. Hence, it is a bad practice to write the code in the above manner. We shouldn’t let a function return None as it always leads to silent errors.
The error will travel to the outer code where the function is called and it will lead to unwanted results. Hence, errors should also not travel. We should always try to implement code in such a manner that it fails fast and crashes if an error occurs. You can observe this in the following code.
def divide(a,b):
try:
return a/b
except ZeroDivisionError:
print("Error occurred. Pass a Non-zero denominator.")
exit()
In this code, we have terminated the program using the exit() function once a ZeroDivisionError occurs. Hence, it will make the program stop as soon as the error occurs and the error will not travel to the outer code.
The statement “Unless explicitly silenced” states that if we want to ignore an error, we can suppress it explicitly. But, it should never travel.
In The Face of Ambiguity, Refuse The Temptation to Guess
This statement in the zen of Python suggests that when the code is not working, there must be an error in the logic we implemented. Hence, only correct logic can fix the error. We should never try to blindly guess why the code isn’t working. It will only lead to time waste. We should always debug the code in a proper manner to rectify the error.
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.
The statement ”There should be one– and preferably only one –obvious way to do it” says that using different ways to implement the same thing leads to confusion and takes more time to write the code.
For example, you might have used the prefix and postfix operators for addition and subtraction in different languages. However, python doesn’t support this. The final output of both prefix and postfix operators is the same. Due to this, new developers trying to learn to code often get confused about when to use the operators. Hence, python avoids the prefix and postfix operators.
The statement “Although that way may not be obvious at first unless you’re Dutch.” refers to the creator of Python Guido Van Rossum as he was Dutch. It simply means that learning and remembering the obvious way to implement anything can be hard unless you are Guido Von Rossum himself.
Now is Better Than Never. Although Never is Often Better Than *right* Now
The statement “Now is better than never” in the zen of Python states that code stuck in an infinite loop or a never-ending loop is worse. The code should always execute in a finite time.
The next statement “Although never is often better than *right* now” says that it is better to wait for a program to complete execution than to terminate it early and get incorrect results. It might also mean that an error should never occur than occurring right now. Hence, never is 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.
The above statements suggest that the implementation of a code should always be simple and understandable. If you cannot explain a code easily, you shouldn’t write that code. If you can explain a code easily to anyone, it’s a good idea to use that approach. For instance, consider the following function that calculates the sum of elements of a list.
from functools import reduce
def calculate_sum(numbers):
return reduce(lambda x, y: x + y, numbers)
You can observe that the above code is very hard to explain as it uses the lambda function and the reduce() method to implement the functionality.
Instead, we can write the same function using just a for loop and the + operator as shown below.
def calculate_sum(numbers):
total = 0
for num in numbers:
total += num
return total
You can observe that this code is far better and is very easy to explain. Hence, we should always prefer this approach.
Namespaces Are One Honking Great Idea — Let’s Do More of Those!
Namespaces give clarity in naming variables in a program. Namespaces allow us to distinguish variables and functions at different instances in a program. Hence, we should always use namespaces correctly in our program.
Conclusion
In this article, we tried to understand the principles for writing good Python code as discussed in the Zen of Python. To learn more about Python programming, you can read this article on the Python walrus operator controversy. You might also like this article on selecting the best cloud data warehouses in 2023.
I hope you enjoyed reading this article. Stay tuned for more informative articles.
Happy Learning!
Disclosure of Material Connection: Some of the links in the post above are “affiliate links.” This means if you click on the link and purchase the item, I will receive an affiliate commission. Regardless, I only recommend products or services I use personally and believe will add value to my readers.