CUSTOMISED
Expert-led training for your team
Dismiss
How to Write Clean Code with Python: A Step-by-Step Guide

13 September 2023

How to Write Clean Code with Python: A Step-by-Step Guide

Writing clean, readable and maintainable code is crucial for any Python developer. Clean code directly impacts the quality, sustainability and extendibility of a software project. This comprehensive guide explores various techniques, best practices and tools to help Python developers write cleaner production-grade code.

This article is part of our support resources for our Clean Code with Python Course. 

What is Clean Code and Why Does it Matter?

Clean code refers to code that is simple, easy to understand and maintain. The hallmarks of clean code include:

  • Readability - Code should clearly communicate logic and intent to other developers.
  • Simplicity - Code should be simple with minimal complexity in logic. Avoid premature optimisations.
  • Modularity - Functionality broken into modules, classes and functions with clear responsibilities.
  • Consistency - Consistent naming, style and coding patterns followed throughout codebase.
  • Documentation - Code documented clearly with docstrings and comments explaining intent and logic.
  • Testing - Tests cover critical code paths and validate functionality thoroughly.
  • DRY (Don't Repeat Yourself) Principle - Eliminate any duplication in code through abstraction.

Writing clean code is critical because:

  • Improves Maintainability - Other developers can easily modify, extend and fix issues in clean code.
  • Reduces Bugs - Clean code with good test coverage has fewer bugs introduced during modifications.
  • Enhances Readability - Clean code reads like simple English making it easier to comprehend.
  • Promotes Collaboration - With readable and modular code, teams can collaborate efficiently.
  • Saves Cost - Clean code requires less time and effort for troubleshooting, maintenance and onboarding of new developers.

Principles for Clean Code in Python

Follow these core principles to write cleaner and more Pythonic code:

Use Descriptive Names

Use readable variable and function names that describe purpose and functionality:

# Good
def calculate_total_price(base_price, tax_rate):
  # logic

# Not as good  
def calc(p, r):
  # logic

Avoid single letter names except common idioms like x, y, i for iterators.

Write Modular Code

Break code into logical modules, classes and functions based on single responsibilities. For example, separate out:

  • Data access layer for database interactions
  • Business logic layer for core processing
  • Presentation layer for UI code

This improves reusability and simplifies testing.

Limit Code Complexity

Keep code simple by limiting complexity:

  • Avoid deeply nested if/else blocks and loops
  • Break code into smaller reusable functions
  • Limit number of parameters for functions

Complex code is harder to understand and maintain.

Leverage Python Features

Utilise built-in Python features instead of reinventing the wheel:

  • Built-in data structures like dict, set over custom types
  • Generators and comprehensions instead of traditional loops
  • with statements for resource management

This results in more idiomatic and cleaner code.

Follow DRY Principle

Eliminate code duplication by abstracting common functionality into reusable functions/classes. For example:

# Bad  
print_report(report1)
print_report(report2)

# Good
def print_report(report):
  # reusable report printing code

print_report(report1) 
print_report(report2)

Use Meaningful Comments

Comments should explain logic and intent, not just describe code:

# Bad  
x = x + 1 # Increment x 

# Good
x = x + 1 # Compensate for border pixel during cropping

Avoid obvious comments that duplicate functionality already evident from the code.

Adopt Pythonic Style

Follow common Python best practices and idioms:

  • Prefer list comprehensions over traditional loops
  • Use context managers like with for resource handling
  • Return tuple early from functions instead of giant if/else blocks

This helps experienced Python developers easily understand code.

Clean Coding Techniques for Python

Let us explore some actionable techniques to improve cleanliness and quality of Python code:

Follow PEP8 Styles

PEP8 is the official Python style guide. Some key points:

  • Use 4 spaces for indentation over tabs
  • Limit lines to 79 characters
  • Follow naming conventions like lower_case_names
  • Use whitespace properly to improve readability

Consistent styling makes code more readable.

Enable Linting

Linters like pycodestyle, pylint and flake8 help enforce styles and find issues:

Linting in Python

Fix linter issues immediately to avoid accumulation of problems.

Apply Automated Formatting

Auto-formatters like black and isort format code to follow standard styles:

# Before black
import numpy as np

def calculate_stats(arr):
   mean = np.mean(arr)
   std_dev = np.std(arr)
   return mean, std_dev 

# After black
import numpy as np

def calculate_stats(arr):
    mean = np.mean(arr)
    std_dev = np.std(arr)
    return mean, std_dev

Consistent styling enhances readability.

Write Docstrings

Write docstrings to document modules, classes, and functions:

def calculate_total(amount, tax_rate, discount):
  """Calculates total with tax and discount.

  Args:  
    amount: Total amount before tax and discount
    tax_rate: Tax rate as percentage
    discount: Discount rate as percentage
  
  Returns:
    Total amount after applying tax and discount.
  """

This provides a built-in way to document code right next to implementation.

Type Hint Function Signatures

Type hints clearly specify input and output types:

def process_data(inputs: List[int]) -> Dict[str, float]:
   # Implementation here

This allows type checking and improves understandability.

Follow Naming Conventions

Use descriptive names and follow conventions:

  • Variables/functions - lower_case_underscored
  • Classes - UpperCamelCase
  • Constants - UPPER_CASE_UNDERSCORED
  • Instance Methods - lower_case_underscored
  • Class Methods - @classmethod lower_case_underscored
  • Dunder Methods - __dunder_method__

Limit Function Parameters

Functions with 3 or fewer parameters are ideal. Avoid functions with more than 5 parameters.

Long parameter lists increase complexity and are hard to use properly.

Handle Resources Properly

Use context managers to manage resources like files/network connections:

with open('file.txt') as f:
  data = f.read()

# File closed automatically when out of scope

This prevents resource leaks and hides error handling.

Write Unit Tests

Write unit tests covering various use cases to catch bugs and prevent regressions:

# test_splitter.py

import unittest
from splitter import split_list

class TestSplitter(unittest.TestCase):

  def test_basic_split(self):
    result = split_list([1,2,3])
    self.assertEqual(result, [[1],[2],[3]])

  def test_empty_list(self):
    result = split_list([])
    self.assertEqual(result, [])

if __name__ == '__main__':
    unittest.main()

Aim for test coverage of all critical parts of the code.

Use Traceback Context

Handle exceptions gracefully and provide context:

try:
  process_data(inputs)  
except ValueError as e:
  print(f"Inputs are invalid: {e}") 

This makes errors easier to understand and debug.

Refactor Ruthlessly

Eliminating code duplication through refactoring is key. For example:

# Bad
process_x(x)  
process_y(y)

# Good
def process(data):
  # reused processing logic

process(x)
process(y)

Refactoring improves maintainability and modularity.

Use Git for Version Control

Use Git & GitHub for:

  • Version control of code history
  • Branching model for feature development
  • Pull requests for change review
  • Issue tracking for tasks, bugs and requests

This enables a streamlined development workflow.

Set Up CI/CD Pipeline

Tools like Jenkins and GitHub Actions enable automating:

  • Running tests and linting on every commit
  • Building and packaging the application
  • Deploying to various environments

This automates quality control and delivery pipeline.

PEP20 - The Zen of Python

PEP20 describes guiding principles for writing Pythonic code:

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.

Internalizing these principles helps in writing more idiomatic Python code.

Formatting Tools for Cleaner Code

Here are some useful code formatting tools:

Tool Purpose
Black Opinionated formatter following PEP8
isort Sorts imports alphabetically
autopep8 Automatically formats to PEP8 style

These tools help uniformly format code and make it more readable.

Linting Tools to Enforce Quality

These linting tools identify issues:

Tool Focus
pycodestyle PEP8 style violations
pyflakes Basic static analysis
pylint Errors, anti-patterns, complexity
flake8 Combines pyflakes, pycodestyle, mccabe

Fixing linter issues improves overall quality.

Testing Tools for Clean Code

Testing tools to validate code:

Tool Description
unittest Inbuilt testing framework
pytest Full-featured testing framework
mock Library for mocks and stubs
coverage Measure test coverage

Thorough testing leads to more robust code.

When to Avoid Refactoring Code

Refactoring techniques make code cleaner and more maintainable. However, avoid refactoring in these cases:

  • Late stages of a release when stability is critical
  • Lack of test coverage increases risk
  • Tight deadlines do not allow time for proper refactoring
  • Frequently changing requirements will necessitate rework
  • Inexperience with codebase increases chances of breaking functionality

Sometimes pragmatism dictates leaving less ideal code alone over refactoring!

Key Takeaways

  • Clean code directly impacts long term maintainability of a project
  • Readability, simplicity, consistency and modularity are hallmarks of clean code
  • Techniques like descriptive naming, proper modularity, limited complexity, reusable functions and DRY principle lead to cleaner code
  • Enable linting and automated formatting to consistently enforce coding standards
  • Comprehensive unit testing and effective use of version control improves quality
  • Refactoring code continuously to eliminate duplication and other "dirty" patterns
  • Mastering clean coding is a lifelong journey! Patience and pragmatism both have a role to play

Writing clean Python code takes knowledge, experience and discipline. But the long term benefits make it incredibly worthwhile. This guide provided techniques to start writing cleaner and more Pythonic code immediately.

Frequently Asked Questions

How is clean code different from just working code?

Clean code is code that is readable, simple, modular and well-tested in addition to being functionally correct. In contrast, working code just focuses on correctness without emphasizing understandability, maintainability and extendibility.

Does clean code take longer to write?

Initially it often does take more time to write clean code due to the additional emphasis on aspects like decomposition, naming, testing etc. However, this pays off in much lower maintenance costs down the line. Automated tools also help speed up writing clean code.

How can I convince others to care about clean code?

Point out tangible benefits like reduced bugs, easier onboarding of new developers, improved ability to add features quickly. Set a positive example by writing clean code yourself. Introduce internal code reviews.

Is 100% test coverage a goal to aim for?

100% coverage should not be the primary goal. Aim for high coverage of critical paths and edge cases. Low value coverage just for the sake of 100% leads to slower tests and unnecessary maintenance of tests.

When starting a new project, should legacy code be rewritten from scratch?

A complete rewrite is often infeasible. Instead, incrementally refactor parts of legacy code touched for new features. Over time, the quality can be improved significantly. A full rewrite also discards business knowledge embedded in legacy code.

Conclusion

This comprehensive guide explored various principles, techniques and tools for writing clean Python code. We looked at practical methods to improve code quality like descriptive naming, modularity, limited complexity, reuse, testing, linting, formatting and refactoring. Mastering these clean coding practices requires diligence and experience. However, the long term maintainability and extendibility benefits are invaluable. Companies like Google, Facebook and Microsoft place a premium on clean coding practices due to the amplified productivity and reduced bugs achieved by their developers. With the techniques covered in this guide, any Python developer can start levelling up their skills and writing more readable, maintainable and Pythonic code.

If you enjoyed this article you might like to read Clean Code with Python: A Beginner's Guide to Writing Readable and Maintainable Code or consider one of our training courses below. 

At JBI Training, we understand that the success of every software project hinges on the quality of the codebase. That's why we're dedicated to equipping developers with the skills they need to produce clean, efficient, and maintainable code. Our comprehensive training programs cover a range of programming languages and practices, ensuring that you're always ahead of the curve in the ever-evolving world of software development.

  • Clean Code with Python: Master the art of writing clean, readable, and maintainable Python code. This course teaches you essential coding principles and best practices to ensure your Python projects are a joy to work on, whether you're a beginner or an experienced developer.
  • Clean Code with Javascript: Elevate your JavaScript skills to the next level with our Clean Code with JavaScript course. Learn how to write clear, concise, and efficient JavaScript code that not only solves problems but also enhances code maintainability.
  • Code Reviews for Developers: Effective code reviews are the cornerstone of collaborative software development. This course provides insights and techniques to conduct and participate in code reviews that result in improved code quality and foster a culture of continuous improvement.
  • Professional Code Practices: Take your coding skills to a professional level. This course covers a wide range of industry-standard practices, tools, and methodologies that will make you a standout developer, whether you're just starting your career or looking to advance it.
  • Python: Get a comprehensive introduction to Python, one of the most versatile and widely used programming languages. This course covers the fundamentals, syntax, and best practices to start building robust Python applications.
  • Python (Advanced): Ready to push the boundaries of Python development? Our advanced Python course delves into more complex topics and advanced techniques, equipping you with the skills to tackle challenging projects and excel in your Python career.

Why Train with JBI Training?

At JBI Training, we don't just teach code; we empower developers to excel in their careers and contribute to high-quality software projects. Our instructors are industry experts with real-world experience, and our courses are designed to be practical, hands-on, and up-to-date with the latest industry trends. Join us on a journey to become a more proficient and effective developer, armed with the knowledge and skills you need to make a lasting impact in the world of software development.

About the author: Daniel West
Tech Blogger & Researcher for JBI Training

CONTACT
+44 (0)20 8446 7555

[email protected]

SHARE

 

Copyright © 2024 JBI Training. All Rights Reserved.
JB International Training Ltd  -  Company Registration Number: 08458005
Registered Address: Wohl Enterprise Hub, 2B Redbourne Avenue, London, N3 2BS

Modern Slavery Statement & Corporate Policies | Terms & Conditions | Contact Us

POPULAR

Rust training course                                                                          React training course

Threat modelling training course   Python for data analysts training course

Power BI training course                                   Machine Learning training course

Spring Boot Microservices training course              Terraform training course

Kubernetes training course                                                            C++ training course

Power Automate training course                               Clean Code training course