Writing Clean and Readable Code in Python: Best Practices and Techniques [Part 1]

Sumbono
10 min readFeb 23, 2023

--

Image by storyset on Freepik

As a Python developer, writing clean and readable code is an essential skill that can help you improve your code quality, readability, and maintainability. Clean code is easy to understand, modify, and debug, which makes it an important aspect of software development. We’ll discuss some of the best practices and techniques for writing clean and readable code in Python, including consistent formatting, meaningful variable names, clear and concise functions, documentation, avoiding code duplication, error handling, using built-in functions, and libraries, testing, refactoring, and peer review.

This article will focus on part 1 of writing code techniques. The consistent formatting, meaningful variable names, clear and concise functions, documentation, avoiding code duplication, error handling, using built-in functions and libraries. While for the testing, refactoring, and peer review will be explained in another article as part 2.

Consistent Formatting

Consistent formatting is essential to writing clean and readable code in Python. It ensures that your code is easy to read and understand, even for other developers unfamiliar with your coding style. Some best practices for consistent formatting include:

  • Indentation: Use consistent indentation throughout your code, typically four spaces for each indentation level.
  • Line length: Limit your line length to a maximum of 79 characters to avoid horizontal scrolling in text editors.
  • Naming conventions: Use consistent naming conventions for variables, functions, and classes to make your code easier to read and understand.

For example, consider the following code snippet:

def calculate_price(quantity, price_per_unit):
total_cost = quantity * price_per_unit
return total_cost

This code follows consistent formatting practices, including four spaces for each indentation level and meaningful variable names.

For naming conventions, here are some additional guidelines for variables, functions, and classes in Python:

Variables:

  • Use descriptive names that convey the purpose and content of the variable.
  • Use lowercase letters separated by underscores for multi-word names. For example: total_amount instead of totalAmount.
  • Avoid using single-letter names except for simple looping constructs.

Functions:

  • Use descriptive names that convey the action or behavior of the function.
  • Use lowercase letters separated by underscores for multi-word names. For example: calculate_total instead of calculateTotal.
  • Use verbs or verb phrases for function names.

Classes:

  • Use a capitalized word for each word in the name, with no underscores. For example: Employee instead of employee_data.
  • Use nouns or noun phrases for class names.

Following the naming conventions and guidelines outlined in the PEP 8 style guide for Python is recommended. This will ensure your code is consistent with the broader Python community and make it easier for other developers to understand and work with your code.

By following these conventions, you can make your code more maintainable and less error-prone, resulting in a more successful and efficient codebase.

Meaningful Variable Names

Using meaningful variable names is another important aspect of writing clean and readable code in Python. When choosing variable names, consider the following best practices:

Be descriptive:

  • Variable names should clearly describe the purpose and content of the variable.
  • Use names specific to the context in which the variable is used. For example, if you have a variable that represents the total amount of a purchase, you might name it as total_purchase_amount.
  • Avoid using abbreviations or acronyms that are not widely understood. If you must use an abbreviation or acronym, ensure it is well-known and commonly used in the domain.

Be consistent:

  • Use consistent naming conventions throughout your codebase to make your code more readable and easier to understand.
  • For example, if you use acamelCase naming convention for function names, use the same convention for variable names.
  • Consistency also means avoiding using the same name for multiple purposes. Using the same variable name for different purposes can lead to confusion and bugs.

Avoid using reserved words:

  • Python has several reserved words that have special meanings and uses within the language.
  • Avoid using these reserved words as variable names, which can lead to unexpected behavior or syntax errors.
  • Some examples of reserved words in Python include if, while, for, def, and class.

For example, consider the above code snippet on the calculate_price function. The variable names quantity and price_per_unit are meaningful and descriptive, making it easy to understand what they represent. The variable name total_cost is also descriptive and accurately conveys the purpose of the variable.

Following these best practices for meaningful variable names in Python can make your code more readable and easier to understand, leading to better code quality and maintainability.

Clear and Concise Functions

Clear and concise functions are another essential aspect of writing clean and readable code in Python. Functions should be easy to understand and use and only perform one task. Some best practices for writing clear and concise functions include:

Keep functions short:

  • Functions should be designed to perform a single task or action. This helps to keep them focused and clear.
  • In general, functions should be kept to around 10–20 lines of code, although this can vary depending on the specific function and its purpose.
  • Shorter functions are easier to read, understand, and maintain than longer functions.

Use descriptive function names:

  • Function names should accurately and clearly convey the purpose of the function.
  • A good function name should be self-explanatory and provide a good idea of what the function does just by reading its name.
  • Avoid using overly generic or vague function names, such as do_something() or process_data() as these provide little information about what the function does.

Avoid side effects:

  • Side effects occur when a function modifies or interacts with something outside its scope, such as a global variable or object.
  • Functions with side effects can be difficult to understand and debug, as it may take time to understand what changes are being made.
  • Ideally, functions should only modify data within their own scope or return a result without affecting any external state.

The function calculate_price is clear and concise and only performs one task. The function name accurately conveys the purpose of the function, and it does not have any side effects.

Documentation

Documentation is an essential aspect of writing clean and readable code in Python. It provides information about the code’s purpose, behavior, and usage, making it easier for other developers to understand and use your code. Some best practices for documenting your code include:

Use docstrings:

  • Docstrings are a way to provide inline documentation for your code in Python.
  • They should be used to document functions, classes, and modules and written clearly, concisely, and informatively.
  • Docstrings should describe the purpose of the code, the inputs and outputs of functions, and any other relevant information that a developer might need to understand and use the code.

Add comments to your code:

  • Comments are used to provide additional information or clarification about specific lines or sections of code.
  • Comments should be used sparingly and only be added when necessary, such as to explain a particularly complex algorithm or provide context for a piece of code.
  • Comments should be written in clear, concise language and easy to understand.

Use consistent formatting:

  • Consistent formatting is important for making your documentation easy to read and understand.
  • Ensure your documentation uses the same indentation, line length, and formatting conventions as the rest of your code.

Update documentation regularly:

  • Documentation should be updated regularly to ensure that it remains accurate and up-to-date.
  • When making changes to your code, update the documentation to reflect those changes.
  • Regularly reviewing and updating your documentation can also help you identify areas of your code that could be improved or simplified.

For example, consider the following code snippet:

def calculate_price(quantity, price_per_unit):
"""
Calculate the total cost based on the quantity and price per unit.

Parameters:
quantity (int): The number of items.
price_per_unit (float): The price per unit.

Returns:
float: The total cost.
"""
total_cost = quantity * price_per_unit
return total_cost

In this code, the function is documented using a docstring that provides information about the function’s purpose, parameters, and return value. This documentation makes it easy for other developers to understand and use the function.

Avoiding Code Duplication

Avoiding code duplication is an important principle of writing clean and readable code in Python. Duplication occurs when the same or similar code is repeated in different parts of the codebase. This can make it harder to maintain the code, as changes in one place may need to be replicated in other places where the same code is used. To avoid code duplication, developers should use functions, modules, inheritance, and composition.

One approach to avoiding code duplication is to use functions and modules. Functions are reusable blocks of code that perform a specific task. They can be called from other parts of the code, reducing the need to duplicate code. Modules are files containing related functions and variables. They can be imported into other parts of the code, allowing developers to reuse code across the entire application.

Another way to avoid code duplication is to use inheritance and composition. Inheritance is a mechanism in object-oriented programming that allows a new class to be based on an existing class, inheriting its attributes and methods. This can be useful for reusing code and avoiding duplication. Composition is a similar concept where a new class comprises existing classes. This allows developers to reuse existing code without having to duplicate it.

Lastly, developers should refactor duplicated code into functions or modules. Refactoring involves improving the design of existing code without changing its functionality. It can make the code easier to read, understand, and maintain. Refactoring can help reduce code duplication by identifying common patterns in the code and creating functions or modules to encapsulate and reuse that code.

In summary, avoiding code duplication is crucial for writing clean and readable code in Python. Using functions and modules, inheritance and composition, and refactoring can help reduce code duplication and improve the maintainability of your codebase.

For example, consider the following code snippet:

def calculate_tax(price):
tax_rate = 0.1
tax = price * tax_rate
return tax

def calculate_total_price(price):
tax_rate = 0.1
tax = price * tax_rate
total_price = price + tax
return total_price

In this code, the tax calculation code is duplicated in both functions. To avoid that, the tax calculation code could be refactored into a separate function or module and reused in both functions.

Error Handling

Error handling is an important aspect of writing clean and readable code in Python. Proper error handling can help you prevent bugs and unexpected behavior in your code and make it easier to debug and maintain. Some best practices for error handling include:

  • Use try-except blocks: In Python, you can use try-except blocks to handle exceptions that may occur during the execution of your code. This allows you to handle errors gracefully and prevent your code from crashing.
  • Be specific with exceptions: When using try-except blocks, handling specific exceptions is important rather than catching all exceptions with a broad except block. This helps you to identify and handle errors more effectively. For example, instead of a generic except block, you could use a more specific exception like FileNotFoundError to handle file-related errors.
  • Use logging: Logging is a useful tool for recording errors and exceptions in your code. It lets you track what’s happening in your code and helps debug issues more effectively. Python’s logging module provides a flexible and customizable way to log errors and other messages in your code. You can use different logging levels to differentiate between different types of messages and configure logging to write to different output sources, such as a file or the console.

For example, consider the following code snippet:

def divide(a, b):
try:
result = a / b
except ZeroDivisionError:
print("Error: division by zero")
return None
return result

This code uses a try-except block to handle the ZeroDivisionError that can occur when dividing by zero. This error handling ensures that the code does not crash and provides a clear error message to the user.

Using Built-in Functions and Libraries

Python has many built-in functions and libraries to help you write clean and readable code. Using built-in functions and libraries can improve code quality and reduce code duplication. Some useful built-in functions and libraries include:

  • String methods: Python has many built-in string methods that are used to manipulate and format strings, such as split(), join(), upper(), lower(), strip(), and more.
  • List and dictionary methods: Python has many built-in methods for lists and dictionaries that are used to manipulate and process data, such as append(), pop(), sort(), keys(), values(), and more.
  • Math functions: Python has many built-in math functions that are used for common math operations, such as abs(), round(), min(), max(), and more.
  • Standard libraries: Python has many standard libraries for common tasks, such as os for working with files and directories, datetime for working with dates and times, re for working with regular expressions, and more.

For example, consider the following code snippet:

import os
import datetime

def backup_file(file_path):
"""
Create a backup of a file with a timestamp in the filename.

Parameters:
file_path (str): The path to the file to be backed up.

Returns:
str: The path to the backup file.
"""
backup_dir = "./backups"

if not os.path.exists(backup_dir):
os.mkdir(backup_dir)

timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
backup_path = os.path.join(backup_dir, f"{file_path}_{timestamp}.bak")
shutil.copy(file_path, backup_path)
return backup_path

This code uses the os and datetime libraries to create a file backup with a timestamp in the filename. The usage of these libraries improves code quality and reduces code duplication by using built-in functions and libraries to accomplish common tasks.

Conclusion

In this article, we have discussed some best practices for writing clean and readable code in Python. By following these practices, you can improve your code’s quality, readability, and maintainability, making it easier to understand, debug, and maintain. Remember to:

  • Use descriptive names for variables, functions, and classes
  • Write clear and concise code
  • Follow PEP 8 style guide
  • Document your code
  • Avoid code duplication
  • Properly handle errors
  • Use built-in functions and libraries

By following these best practices, you can write high-quality code that is easy to read, understand, and maintain and improve your skills as a Python developer.

--

--

Sumbono

Interested in Backend, Data Engineering and Analytics. Have experience in building end-to-end data pipelines.