Pythonic Way of Writing Code

Pythonic Code

In most programming languages, we often come across a claim saying that it’s the most powerful language. Well, this statement seems to be more subjective and why is it so? This is because a program written in one language can be coded in another language.

The syntax may vary from language to language, but there is no algorithm that one language can implement and the other language can’t.  In this article, we are going to see some ways that Python has to offer in terms of best practices, simplicity, and readability, which can be stated as Pythonic.

The Gist of Pythonic Code

There are various ways or design patterns in Python just like any other language. Python in itself uses syntax that reads very close to English and we can find numerous articles or online reviews mostly from people coming from other languages that Python can be learned in a few weeks and so on. Well, that is not true for any language and certainly not for Python too.

Pythonic refers to the idiomatic coding practices specific to Python, which are indeed more than just using Python syntax and using the standard library.

Pythonic is also referred to as idiomatic, which means writing Python code based on the idea of it being aligned with the features provided by the standard library. This statement can be different for different programmers, and it’s certainly not an absolute guideline for anyone.

It’s the idea of writing Python like an experienced programmer with best practices and techniques, just like any other language, which is generally followed by a huge community.

Why do we need Pythonic code at all?

Whenever we write a program, it’s intended to be executed correctly. There are multiple ways of writing a program, but some ways can be seen as being the “more” right way. It’s true especially in the case of Python since it uses minimalistic syntax and is quite readable. So, if we use it wrong or the “less” right way, it is often hard to be overlooked.

Writing code the “more” right way has many advantages. Some of them can be stated as:

  • We are taking advantage of thousands of very smart developers who have years of experience writing Python and who have contributed back to the open-sourced language.  It’s certainly a great idea to leverage the expertise that they have acquired working with the language for a very long time, implementing best practices and idiomatic ways to use Python.
  • Talking about CPython specifically, it expects a certain type of code implementation for efficiency purposes since it has been tuned for this very purpose for many operations under the hood. For example, we can create a sub-list from a list by using a for-loop, or we can use slicing for the same purpose. Slicing is slightly better since it’s expected to work in the exact same way that we intended.
  • A piece of code should be easy-to-read and comprehensive. Say, for example, when we see common patterns like list comprehensions, we can understand the code much faster even before parsing all the symbols. On the contrary, in a non-pythonic way, we have to analyze the entire code to understand how it works. Thus, writing a piece of code in an idiomatic way is often cleaner and simpler.

These are the obvious advantages for us, as Python developers. However, there are also the less-obvious or broader benefits such as:

  • When we run an open-sourced project, it’s easier for people to contribute if use the best practices. The people contributing to our project would be stoked to see the code being written in smart ways. One of the projects that missed out on this idea was the traditional PyPI. When we pip install any package, it’s the PyPI that we are running. It’s been around for years, but it was very difficult to find open-source contributors for it. Well, the PyPI source code lacked idiomatic practices. It consisted of thousands of code lines in a single file and a similar code base. So, when people tried to contribute to making it better, they had a hard time going through such code.

On a good note, it was rewritten and made available at PyPI’s official website making use of the best practices, and modern idioms, certainly with a lot more contributors this time.

  • Working with a closed source code such as for an organization or a company, only the best developers are expected to work and to be retained. So, the best coding practices and consistency in a project provide those developers the benefit of working on a much more idiomatic, understandable, and readable code.

Code Examples of the Pythonic Way

Let’s try to go through some examples to get an overview of the Pythonic code that we discussed previously in this article.

1. Naming Conventions

Variables which are also referred to as identifier names are used across all programming languages as a fundamental part. Usually, there are no fixed guidelines for naming our variables, but following a pattern helps.

PEP8 provides some of the best practices or a style guide for naming our variables that follows the Pythonic way. Even a short glance at them can provide a good overview of the kind of code being read. Some examples are provided below.

Naming ConventionsFrom PEP 8 Style Guide
Packagesutilities
Modulesdb_utils, dbutils, db_connect
ClassesCustomerDetails
Functionscreate_order
Variablesorder_id
ConstantsSHIPPING_COST
PEP 8 Style Guide

2. String Formatting by using f-strings

Using strings to print out values or return statements with interpolated strings including expressions is a common pattern in Python. Earlier, the strings were concatenated or joined by using the + operator which resulted in a very long line of code that looked too cluttered and often confusing. The problem was soon addressed and some very neat solutions were provided by the language.

The f-strings were introduced in Python 3.6 which provided an even better solution to the above problem. The f-strings can be considered as an improvement to writing strings in Python given the fact that the code being written with f-string formatting will not be backwards compatible, but implementing them fulfils the criterion of being Pythonic. Let’s go through some examples to get an overview.

first_name, age, job = "John", 33, "programmer"

# Method 1: String Concatenation
print(first_name + " " + "is a" + " " + str(age) + " " + "year old" + " " + job)

# Method 2: % Conversion specifier
print("%s is a %d year old %s" % (first_name, age, job))

# Method 3: Using format: Until Python 3.6
print("{0} is a {1} year old {2}".format(first_name, age, job))

# Method 4: The Pythonic Way: From Python 3.6 and above
print(f"{first_name} is a {age} year old {job}")

"""
Output:

John is a 33 year old programmer
John is a 33 year old programmer
John is a 33 year old programmer
John is a 33 year old programmer

"""

3. Using enumerate() rather than len() or range () functions with for-loops

Oftentimes, we have to use for-loops to iterate over an iterable object in Python such as lists, strings, or tuples, and indexing through them is also required. There are more than a few ways to achieve this. Some of the common patterns use len() or range() functions to access the index of those iterables. Python has a built-in enumerate() function to perform this very operation, which can be deemed as Pythonic that provides access to the index directly rather than coding it up using multiple functions.

# ------------------------------
# Looping and Indexing through
# -----------------------------

# Method 1
greet = "hello"
i = 0
for eachChar in greet:
    print(i, eachChar)
    i += 1

"""
0 h
1 e
2 l
3 l
4 o

"""

# Method 2: A better way
greet = "there"
for idx in range(len(greet)):
    print(idx, greet[idx])

"""
0 t
1 h
2 e
3 r
4 e

"""

# Method 3: The Pythonic way: enumerate()
greet = "hello"
for idx, eachChar in enumerate(greet):
    print(idx, eachChar)

"""
0 h
1 e
2 l
3 l
4 o

"""

4. Using List Comprehensions instead of for-loops

List comprehensions are unique to Python. It’s a way for us to quickly create lists with Python instead of looping and using append. It provides a shorter syntax to create a brand new list based on the items contained in the original list, or the iterable object to be specific. Below is the example using the append function and the more Pythonic list comprehensions. Note that it must not be overused since we don’t want too much logic in a single line of code, but it’s really helpful in various situations. It makes our code concise and readable.

# Using loops
my_list = []
for char in "hello":
    my_list.append(char)
print(my_list)  # ['h', 'e', 'l', 'l', 'o']


# The Pythonic Way: Using List Comprehensions
my_list1 = [char for char in "hello"]
print(my_list1)  #  ['h', 'e', 'l', 'l', 'o']

5. Merging Dictionaries

Dictionaries are used all over in Python. They are one of the most important data structures and are utilized in numerous ways. Key | Value pairs in dictionaries are the building blocks and performing multiple operations on them is quite common in Python. For this example, we will be looking at merging dictionaries conventionally or procedurally as well as a few Pythonic ways.

# Declaring two variables for dictionaries
customer_details = {"name": "john", "age": 34, "email": "[email protected]"}
order_items = {"item1": "apple", "item2": "orange"}

# Method 1: Not So Pythonic: Using Loops
order_details = {}
for i in customer_details:
    order_details[i] = customer_details[i]
for i in order_items:
    order_details[i] = order_items[i]

print(f"Result_one: {order_details}")

# The Pythonic way: Spreading out and merging using **kwargs
order_details = {**customer_details, **order_items}
print(f"Result_two: {order_details}")

# Python 3.10 Updated:  Union Operator (with | pipe character)
# The Pythonic Way
order_details = customer_details | order_items
print(f"Result_three: {order_details}")

"""
Output:

Result_one: {'name': 'john', 'age': 34, 'email': '[email protected]', 'item1': 'apple', 'item2': 'orange'}  
Result_two: {'name': 'john', 'age': 34, 'email': '[email protected]', 'item1': 'apple', 'item2': 'orange'}  
Result_three: {'name': 'john', 'age': 34, 'email': '[email protected]', 'item1': 'apple', 'item2': 'orange'}
"""

Conclusion

In all programming languages, there are best practices specific to them. Python, being one of the most commonly used languages is no different. It has its battle-tested techniques and writing style. Writing Pythonic code makes our code not only simpler and readable but also easy to maintain.

Idiomatic Python provides an easy-to-recognize design pattern that makes programming a seamless experience with minimum confusion. In this article, we went through some of them to get an overview of the Pythonic ways.

There are numerous other examples and it will only keep growing over time. Pythonic truly does hold an important place in the Python developer community.