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:
- Improved readability and maintainability of code.
- Consistent styling across developers and teams.
- Professional look and feel of code.
- Easy to understand logic and program flow.
- Helps avoid common errors and bugs.
- Promotes good programming practices.
- Enables better collaboration between developers.
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
- Use 4 spaces per indentation level (no tabs).
- Indent after function definitions, loops, if statements etc.
- Continued lines should align vertically using the same 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
- Limit lines to 88 characters maximum.
- Use parentheses, hanging indents, and line continuation for long lines.
# 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
- Surround operators and assignments with spaces for readability.
- Do not use extraneous whitespace inside parentheses, brackets or braces.
# 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
- Use blank lines sparingly to separate logical sections of code.
- One blank line between top level function and class definitions.
- One blank line between method definitions in a class.
- No blank lines inside brackets, braces, or parentheses.
# 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:
- Standard library imports
- Third-party package imports
- 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.