An Introduction to the Art of Computer Programming Using Python in the Age of Generative AI

XVI. Best Practices and Coding Conventions

Beautiful is better than ugly.
Tim Peters, Zen of Python

Introduction

When you begin programming, the primary challenge is writing code that a computer can execute without errors. But as applications grow larger, a new challenge emerges: writing code that people—including your future self—can understand and maintain. Achieving clarity, readability, and consistency is crucial for collaboration and reducing defects. Well-crafted code is not only functional but also elegant and maintainable, ensuring it can evolve over time.

Python explicitly embraces this philosophy. You can view the language's guiding principles by running:


import this
# This prints "The Zen of Python", a collection of 19 software principles.
        

Consistent Naming Conventions

Using clear, descriptive names for variables, functions, methods, and classes is one of the simplest yet most impactful ways to make your code more readable. Good naming conventions reduce cognitive load by clearly communicating the purpose of each piece of code. Follow consistent styles, such as using snake_case for functions and variables, PascalCase (or CapWords) for classes, and UPPER_CASE for constants.


# Good naming example
MAX_RETRIES = 5

class Book:
    def __init__(self, title, author, isbn):
        self.title = title
        self.author = author
        self.isbn = isbn

# Bad naming example
class b:
    def __init__(self, t, a, i):
        self.t = t
        self.a = a
        self.i = i
        

Code Formatting and PEP 8

Python’s official style guide, PEP 8, offers guidelines for consistent code formatting such as indentation (4 spaces), line lengths (79 characters), import order, and whitespace usage. Adhering to these standards makes your code appear clean and helps other Python developers read, understand, and review it more easily. You can use automated tools like flake8, black, or ruff to check and enforce PEP 8 rules.


# PEP 8 compliant code
class Book:
    def __init__(self, title, author, isbn):
        self.title = title
        self.author = author
        self.isbn = isbn

# Non-compliant code
class book: def __init__(self, title,author,isbn): self.title=title;self.author=author;self.isbn=isbn
        

Modern Best Practice: Type Hinting

Since Python 3.5, Type Hinting has become a standard practice. While Python is dynamically typed, adding type hints makes your code self-documenting and allows IDEs to catch bugs before you run the code.


# Without type hints
def calculate_total(price, tax):
    return price * (1 + tax)

# With type hints
def calculate_total(price: float, tax: float) -> float:
    return price * (1 + tax)
        

Writing Docstrings

Well-written docstrings describe the purpose, parameters, and return values of functions, methods, and classes. This makes your code self-documenting and easier to maintain, especially for larger projects or open-source collaborations. Python docstrings often follow the Google or NumPy style conventions.


class Book:
    """
    A class representing a book in a bookstore.
    """
    def __init__(self, title: str, author: str, isbn: str):
        """
        Initializes the Book instance.

        Args:
            title (str): The title of the book.
            author (str): The author of the book.
            isbn (str): The ISBN number of the book.
        """
        self.title = title
        self.author = author
        self.isbn = isbn
        

Resource Management: Context Managers

A common source of bugs is failing to close resources like files or network connections. The best practice in Python is to use Context Managers (the with statement). This ensures resources are cleaned up automatically, even if errors occur.


# Bad practice: Manually opening and closing
f = open('data.txt', 'w')
f.write('hello')
f.close() # If an error happens before this, the file stays open!

# Good practice: Context Manager
with open('data.txt', 'w') as f:
    f.write('hello')
# File is automatically closed here, even if an error occurs.
        

Avoiding Global Variables

Global variables can lead to unintended side effects and unpredictable behavior, especially in larger programs. By scoping variables to classes, functions, or modules, you ensure that behavior is more predictable, debugging is less painful, and your design is more modular.


# Bad practice: Using a global variable
inventory = []

class BookStore:
    def add_book(self, book):
        global inventory
        inventory.append(book)

# Good practice: Avoiding global variables
class BookStore:
    def __init__(self):
        self.inventory = []

    def add_book(self, book):
        self.inventory.append(book)
        

Using Version Control Systems

For any project beyond trivial size, a version control system such as Git is essential. It allows you to track changes, revert to previous states when issues arise, and collaborate seamlessly with other developers.


# Basic Git Workflow
git init
git add .
git commit -m "Refactor BookStore to use dependency injection"
        

Leveraging AI for Refactoring

Generative AI is an excellent tool for enforcing best practices. You can paste working but "messy" code into an LLM and ask it to apply PEP 8, type hints, and docstrings.

Generative AI Insight: Clean code is the best prompt. If your variable names are descriptive (e.g., user_input_text instead of x) and your functions have type hints, AI coding assistants can understand your intent much better, resulting in more accurate code suggestions.

Additional Best Practices

These practices will help you create more stable, comprehensible, and maintainable applications—ultimately making your job as a developer far easier in the long run.

Back to Home