Python PEP 8 Formatting Tutorial

Vigneswaran SVigneswaran S
5 min read

PEP 8, or Python Enhancement Proposal 8, is the official style guide for Python code. It provides a set of recommendations on how to write clear, readable, and consistent Python code. Adhering to PEP 8 makes your code easier to understand, maintain, and collaborate on, both for yourself and for others.

This tutorial will cover the most important aspects of PEP 8 formatting.

Why PEP 8?

  • Readability: Consistent formatting makes code easier to read and understand, reducing cognitive load.

  • Maintainability: Well-formatted code is simpler to debug and modify.

  • Collaboration: When multiple developers work on a project, a unified style ensures consistency across the codebase.

  • Professionalism: Following established conventions demonstrates good coding practices.

Key Formatting Rules

1. Indentation

Use 4 spaces per indentation level. Never use tabs.

Good:

def greet(name):
    if name:
        print(f"Hello, {name}!")
    else:
        print("Hello, stranger!")

Bad:

def greet(name):
  if name: # Two spaces
    print(f"Hello, {name}!")
    else: # Tab
        print("Hello, stranger!")

2. Line Length

Limit all lines to a maximum of 79 characters. For docstrings and comments, limit to 72 characters. This helps readability, especially when viewing code side-by-side or on smaller screens.

Use parentheses for implicit line continuation.

Good:

def calculate_long_expression(a, b, c, d, e, f):
    result = (a + b * c -
              d / e + f)
    return result

my_long_string = (
    "This is a very long string that needs to be "
    "broken into multiple lines for readability."
)

Bad:

def calculate_long_expression(a, b, c, d, e, f):
    result = a + b * c - d / e + f # Line is too long
    return result

3. Blank Lines

Use blank lines to logically separate sections of code.

  • Surround top-level function and class definitions with two blank lines.

  • Surround method definitions inside a class with one blank line.

  • Use blank lines in functions to indicate logical sections.

Good:

import os

class MyClass:
    def __init__(self, value):
        self.value = value

    def my_method(self):
        # First logical block
        print("Doing something...")

        # Second logical block
        if self.value > 10:
            print("Value is large.")
        else:
            print("Value is small.")

def another_function(arg1, arg2):
    total = arg1 + arg2
    return total

4. Imports

  • Imports should usually be on separate lines.

  • Imports should be grouped in the following order:

    1. Standard library imports.

    2. Third-party imports.

    3. Local application/library specific imports.

  • Each group should be separated by a blank line.

Good:

import os
import sys

import pandas as pd
import numpy as np

from my_package import my_module
from my_package.my_module import MyClass

Bad:

import os, sys # Multiple imports on one line
import pandas as pd
from my_package import my_module # Mixed groups

5. Whitespace in Expressions and Statements

  • Avoid extraneous whitespace immediately inside parentheses, brackets or braces.

  • Avoid extraneous whitespace immediately before a comma, semicolon or colon.

  • Avoid extraneous whitespace immediately before the open parenthesis that starts the argument list of a function call.

  • Avoid extraneous whitespace immediately before the open bracket that starts an indexing or slicing.

  • Always surround binary operators with a single space on either side.

Good:

spam(1, 2)
dict['key'] = list[index]
x = 1
y = 2
long_variable = x * 2 + y / 3

Bad:

spam( 1, 2 ) # Extraneous whitespace
dict [ 'key' ] = list [ index ] # Extraneous whitespace
x = 1 # No space around assignment
y=2 # No space around assignment
long_variable = x*2 + y/3 # No space around operators

6. Naming Conventions

  • Modules: lowercase_with_underscores

  • Packages: lowercase_with_underscores

  • Classes: CapWords (CamelCase)

  • Functions: lowercase_with_underscores

  • Variables: lowercase_with_underscores

  • Constants: ALL_CAPS_WITH_UNDERSCORES

  • Methods: lowercase_with_underscores

  • Instance variables: _single_leading_underscore (for non-public methods/attributes)

  • Private methods/attributes: __double_leading_underscore (name mangling)

Good:

MAX_CONNECTIONS = 100

class UserProfile:
    def __init__(self, username):
        self.username = username
        self._internal_id = generate_id() # Non-public

    def display_profile(self):
        print(f"User: {self.username}")

def calculate_average_score(scores):
    total = sum(scores)
    return total / len(scores)

7. Comments

  • Comments should be complete sentences.

  • Block comments apply to some (or all) code that follows them, and are indented to the same level as that code.

  • Inline comments are on the same line as a statement. They should be separated by at least two spaces from the statement.

Good:

# This is a block comment explaining the next section of code.
# It should be indented to the same level as the code it describes.
x = 10  # This is an inline comment.

def process_data(data):
    """
    Processes the input data.

    Args:
        data (list): A list of numerical data.
    """
    # Initialize a counter for processed items.
    processed_count = 0
    for item in data:
        # Perform some operation on each item.
        processed_count += 1
    return processed_count

8. Docstrings

  • Write docstrings for all public modules, functions, classes, and methods.

  • Use triple double quotes ("""Docstring goes here.""").

  • For one-line docstrings, keep it on a single line.

  • For multi-line docstrings, the opening quotes are on a separate line, the summary line follows, then a blank line, then the rest of the description, and the closing quotes are on their own line.

Good:

def add_numbers(a, b):
    """Add two numbers and return their sum."""
    return a + b

class Calculator:
    """
    A simple calculator class.

    This class provides basic arithmetic operations.
    """
    def subtract(self, a, b):
        """
        Subtracts two numbers.

        Args:
            a (int): The first number.
            b (int): The second number.

        Returns:
            int: The difference between a and b.
        """
        return a - b

Tools for PEP 8 Compliance

While manual adherence is good, tools can automate and check your code for PEP 8 compliance.

  • Flake8: A popular tool that wraps PyFlakes, pycodestyle (which checks PEP 8), and Ned Batchelder's McCabe script. It's great for linting and finding style errors.

    To install:

      pip install flake8
    

    To run:

      flake8 your_script.py
    
  • Black: An uncompromising code formatter. Black formats code automatically, making it opinionated and ensuring consistent style across projects without manual intervention.

    To install:

      pip install black
    

    To run:

      black your_script.py
    

    Or to check without changing files:

      black --check your_script.py
    

Conclusion

Following PEP 8 is a fundamental practice for any Python developer. It significantly improves the readability, maintainability, and collaborative nature of your code. While it might seem like a lot to remember at first, consistent practice and the use of automated tools will make it second nature. Happy coding!

0
Subscribe to my newsletter

Read articles from Vigneswaran S directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vigneswaran S
Vigneswaran S

With profound zeal, I delve into the essence of coding, striving to imbue it with beauty and clarity. Conjuring wonders through code is, to me, a delightful pastime interwoven with an enduring passion.