Skip to content

Mastering PEP 8: Python Code Style Guide Essentials

Updated: at 01:35 PM

PEP 8 is Python’s official style guide, providing a set of rules and coding conventions to standardize code across different Python projects and developers. It covers topics including naming conventions, code layout, whitespace usage, programming practices, and documentation. Following PEP 8 guidelines helps create Python code that is professional, simple, consistent, and easy to understand. The benefits of PEP 8-compliant code include:

This guide will break down the key components of PEP 8, providing actionable tips and Python code examples for writing clean code that adheres to its standards. Both novice and experienced Python programmers can use this as a practical reference when writing new code or refactoring existing code.

Naming Conventions

PEP 8 contains specific guidelines for naming variables, functions, classes, modules etc. Using clear, descriptive, and consistent naming helps improve code understandability.

Use lowercase with underscores

Function, variable, and module names should be in all lowercase, using underscores to separate words:

# Correct conventions
my_variable = 'Hello'

def calculate_sum(numbers):
  ...

import helper_module

Class names should be in CamelCase format:

# Class name uses CamelCase
class MyClassName:
  ...

Avoid single letter names

Single letter variables like ‘x’ or ‘y’ can be confusing. Use more descriptive names:

# Avoid
x = 1
y = 2

# Preferred
number = 1
counter = 2

Name booleans and constants appropriately

Booleans should be named using ‘is’ or ‘has’ prefixes. Constants should be all caps with underscores:

# Booleans
is_active = True
has_permissions = False

# Constants
MAX_SIZE = 100
CONNECTION_TIMEOUT = 50

Use verbs for function names

Function names should clearly describe the action being performed and use a verb to start:

# Good function names
def get_user_data():
  ...

def calculate_average(numbers):
  ...

Code Layout and Whitespace

Proper spacing, indentation, and placement of code blocks improves code organization and visual appearance.

Indentation

# Aligned indentation

if user.is_active():
  print('Active user found')
  send_notification()
  update_status('Active')

for item in list_of_items:
  process_item(item)
  save_changes()

Line length

# Use parentheses
long_function_call_with_many_args(arg1, arg2, arg3,
                                 arg4, arg5)

# Hanging indents
long_string = ('This is a very long string that goes over '
               'the 88 character limit')

# Line continuation
long_calculation = (some_value + some_other_value -
                    some_condition)

Whitespace

# Spaces around operators
x = 1 + 2
value = (3 * 4) - 5

# No extra whitespace
my_list = [1, 2, 3]
my_dict = {'key': 'value'}

# Spaces separating items
if x == 1 and y == 2:
  ...

Blank lines

# Logical blank line spacing

def process_data():
  data = get_data()

  # Blank line
  results = analyze(data)

  return results


class MyClass:

  def __init__(self):
    ...

  # Blank line
  def method1(self):
    ...

  def method2(self):
    ...

Imports

Imports should be organized and located at the top of the file below module documentation.

Group imports

Imports should be grouped in the following order:

  1. Standard library imports
  2. Third-party package imports
  3. Local application imports

Each grouping should be separated by two blank lines:

# Standard library
import os
import sys
import json


# Third-party
import numpy as np
import pandas as pd


# Local imports
from . import helper
from .utils.converters import convert_to_float

Avoid relative package imports

Use the absolute package name instead of relative imports like from .utils import helper.

Limit line length

Break long import statements across multiple lines, ideally limiting to 88 characters. Use parentheses and hanging indents when needed:

# Long imports
from third_party_lib.specific_package import (
  VeryLongModuleName, AnotherVeryLongName)

from my_local_package.utils.modules import (
  my_module, my_other_module, helper_functions)

Programming Practices

PEP 8 contains several guidelines for best practices when coding in Python:

Avoid extraneous code

Remove any code that does not get used - old debug statements, unnecessary comments, unused variables or imports etc. They add clutter and increase file size needlessly.

Use meaningful comments

Comments should explain complex code or algorithms. Avoid extraneous comments that just restate the code.

# Good comments

# This converts the dataframe columns to numeric using partial function application
cols_to_numeric = partial(convert_cols, df=dataframe,
                         cols=['col1', 'col2'])

# Bad comments
x = x + 1 # Increment x by 1

Modularize code into functions

Break code into logical chunks using functions for better organization. Functions should do one thing only.

Avoid nested control flows

Nested if statements, loops, and comprehensions can make code hard to read. Use functions to encapsulate the logic.

Use context managers

Use context managers like ‘with’ for resource handling instead of try/finally blocks.

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

# Without context manager
f = open('file.txt')
try:
  data = f.read()
finally:
  f.close()

Prefer enumerate over range

Use enumerate() to get index values when iterating:

for i in range(len(list_data)):
  ...

# Better
for i, val in enumerate(list_data):
  ...

Documentation

Proper documentation makes code easier to use and understand. PEP 8 recommends using:

Docstrings

Docstrings provide help text and usage information. Use triple double-quotes and include Args/Returns/Raises sections:

def calculate_area(radius):
  """Calculate area of a circle.

  Args:
    radius (int/float): The radius of the circle.

  Returns:
    area (float): The calculated circle area.
  """

  area = math.pi * radius**2
  return area

Comments

Comments improve understandability and provide explanation. Use sparingly inside functions/classes:

# Connects to the data source
conn = connect_db()

data = get_records(conn) # Returns all records

Version Docstrings

While not an official PEP 8 recommendation, it is good practice to start files with a module level docstring containing version information:

"""my_module.py

Performs X task.

Version: 1.0
Author: Mark Anthony Llego
Created: 01-10-2021
"""

Tools for PEP 8 Compliance

Linters

Using a linter like flake8 will automatically check your code and catch PEP 8 issues/violations. Run flake8 against your code regularly to enforce compliance.

Auto-formatters

Tools like Black can reformat your code to conform to PEP 8 standards. This automates styling fixes like proper indentation.

Conclusion

PEP 8 contains comprehensive style guidelines for writing clean, readable, and professional Python code. Following its conventions improves collaboration between developers working on shared codebases. This guide provided actionable tips and examples for writing PEP 8-compliant code covering topics like naming, whitespace, imports, practices, and documentation. Writing high quality Python code using these standards ensures code maintainability, consistency, and better teamwork.

Example Code

Here is an example Python script demonstrating various PEP 8 conventions:

"""
example.py

Simple script with PEP 8 examples.

Author: Mark Anthony Llego
Created: 01-10-2021
"""

# Standard library
import json
import math
import sys


# Third party
import numpy as np


# Local application
from mypackage.utils import helper


# CONSTANTS
PI = 3.141592653


# Function with docstring
def calculate_area(radius):
  """Calculate area of a circle.

  Args:
    radius (int/float): The circle radius

  Returns:
    area (float): The circle area
  """

  area = PI * radius**2
  return area


# Class with docstring
class Circle:
  """Class to represent a geometric circle"""

  def __init__(self, radius):
    self.radius = radius

  def area(self):
    """Compute circle area"""
    return calculate_area(self.radius)


def main():
  """Main function"""

  # Open file
  with open('data.json') as f:
    data = json.load(f)

  print(data)

  # Create instance
  c = Circle(5)
  print(f'Area: {c.area():.2f}')


if __name__ == '__main__':
  main()

This example applies several PEP 8 guidelines discussed in this guide. The revised article incorporates your suggestions to improve accuracy and adherence to PEP 8. Let me know if you would like me to modify or expand any other sections.