Quick answer: PEP 8 is Python’s official style guide: four-space indentation, snake_case for functions and variables, PascalCase for classes, UPPER_CASE for constants, two blank lines between top-level definitions, lines soft-capped at 79 characters, and name everything so the code reads like English. Clean style is not decoration — it is what makes your code fixable six months later.

Finale of Module 1 of our Python series. If you can set up an environment, use the core types, write branches and loops and functions, this article turns your scripts into code other people can maintain.

Why style is a career topic, not a cosmetic one

Two facts: code is read far more than it is written, and style consistency is the first thing reviewers and interviewers see. PEP 8 exists so that all Python codebases look alike — a style “dialect” you learn once, then read any project. Tooling makes it free: an autoformatter does 95 percent of the work.

Naming conventions (the 80 percent of PEP 8)

ThingConventionExample
Variable / functionsnake_caseinvoice_total, parse_row
ClassPascalCaseInvoiceParser
ConstantUPPER_SNAKEMAX_RETRIES = 3
Module / fileshort snake_caseinvoice_utils.py
_leading underscoreinternal use_debug_cache
__dunder__reserved for Pythondo not invent your own

Bad: x2, temp1, doStuff. Good: sales_tax_rate, all_order_lines. The name should survive without a comment; if it cannot, either the name or the design is wrong.

Formatting rules you will actually be checked on

# two blank lines between top-level definitions
import math


def cloud_radius(base):
    """One-sentence docstring: what, not how."""
    return base * math.pi          # spaces around operators, after commas


MAX_CONNECTIONS = 5                  # constants at the top, UPPER

def connect(host, port=5432, retries=MAX_CONNECTIONS):
    if retries > MAX_CONNECTIONS:    # four-space indent, one level
        retries = MAX_CONNECTIONS
    return host, port, retries
  • Four spaces per indent level; never tabs mixed in.
  • Indent continuation lines when a call wraps.
  • Spaces after commas, around = in assignments, none around = for keyword arguments in a call (connect(host, port=5432)).
  • Import order: standard library first, blank line, everything else.

Comments and docstrings

Comments explain why; the code already says what:

# Retry logic exists because the school API rate-limits bursts.
time.sleep(2)                       # <- poor comment: just restates the call

Every public function gets a docstring — the first line states the contract in one sentence (you wrote these in Article 4):

def flatten(rows):
    """Return a single list from a list of lists."""

Idiomatic Python: five upgrades from beginner style

Each snippet below is a fragment — variables like tasks, name, nums are assumed to exist — and each replacement taken together is proven end-to-end in the complete example that follows.

import time                    # needed for the example call below

# 1. truthiness instead of len() == 0
if not tasks:                  # not if len(tasks) == 0:
    print("Empty")

# 2. f-strings instead of concatenation
print(f"{name} scored {score}")     # not print(name + " scored " + str(score))

# 3. direct tuple unpacking
low, high = min(nums), max(nums)    # not two separate lines with temp vars

# 4. enumerate over manual counters
for i, task in enumerate(tasks, start=1):
    print(i, task)

# 5. comprehensions over append-loops
evens = [n for n in range(20) if n % 2 == 0]

Each idiom is shorter AND clearer. Read Effective Python or any style library’s source code for the rest of them.

Complete executable example

# invoice_style.py — Module 1 finale: everything, styled
import math

TAX_RATE = 0.18              # constant, not magic number scattered in code


def invoice_total(prices):
    """Return the taxed total for a list of unit prices.

    Empty input is valid and returns 0.0.
    """
    if not prices:
        return 0.0
    subtotal = sum(prices)
    return round(subtotal * (1 + TAX_RATE), 2)


def report(label, prices):
    """Print a styled one-line summary; returns the total for reuse."""
    total = invoice_total(prices)
    print(f"{label:>10}: {total:>9} ({len(prices)} items)")
    return total


def is_valid_price(p):
    """Prices must be positive and finite."""
    return p > 0 and math.isfinite(p)


line_items = [499.0, 1299.50, 89.99]
raw_input_prices = [499.0, -1, 1299.50]          # cleaning pipeline
cleaned = [p for p in raw_input_prices if is_valid_price(p)]

report("Cart", line_items)
report("Cleaned", cleaned)

Line by line: TAX_RATE is uppercase and defined once; every function has a docstring contract; report both prints AND returns so callers can reuse the number; the list comprehension replaces three lines of manual filtering; math.isfinite rejects NaN and infinity which would silently poison the sum.

Common mistakes and edge cases

  • Naming that lies — data2 or temp_file_final2 rots instantly. Rename until the identifiers need no comment.
  • Mixed tabs and spaces — a file can look aligned and still raise TabError (Python 3 refuses to guess). Configure the editor to insert spaces.
  • Copy-pasting code instead of a function — one bug then lives in three places. If you paste a block a second time, extract a function.
  • Comments that restate code — i += 1 # increment i. Delete them; only why comments survive review.
  • Standing style up by hand forever — run an autoformatter (black or ruff format in the terminal: python -m black invoice_style.py) and a linter (python -m ruff check .) as part of daily work. Both are one pip install away.

Key takeaways and challenge

  • PEP 8 in one line: snake_case names, four-space indents, constants uppercase, self-explaining code, minimal comments that say why.
  • Autoformatters make style free — black / ruff.
  • Idioms (f-strings, truthiness, comprehensions, enumerate) are style and speed together.

Challenge: take any earlier challenge script (fizzbuzz.py or todo-board.py), run black on it, then read the diff — every change it makes is PEP 8 you can copy into your habits. Rename at least one variable per script so the name alone explains the value.

This closes Module 1 (Foundations). Module 2 next: standard library and sysadmin automation. Want one-to-one help getting ramped in Python? Ampersand Academy offers hands-on training.

What is PEP 8 and is it mandatory?

PEP 8 is Python’s official style guide, the reference for naming, indentation, and imports. It is not enforced by the language, but most teams and reviewers treat it as the standard.

What naming convention does Python use?

snake_case for functions, variables, and modules; PascalCase for classes; UPPER_SNAKE_CASE for constants; a leading underscore marks internal-use names.

How many spaces per indent level in Python?

Four spaces, per PEP 8. Never mix tabs and spaces in the same file: Python 3 raises TabError when the two are mixed inconsistently.

Do I need to fix PEP 8 violations by hand?

Rarely. Autoformatters such as black or ruff format reformat the file mechanically, and linters such as ruff check flag naming and unused imports.

What makes code Pythonic?

Using the language’s idioms: truthiness instead of len() == 0, f-strings instead of concatenation, tuple unpacking, enumerate for counted loops, and comprehensions instead of append-heavy loops.

Last updated on · Written by