Naming Style and Readability
What You'll Learn
Python's official naming conventions, how to write code that reads like prose, and when and how to document your code.
Why Readability Matters
"Code is read far more often than it is written." — Guido van Rossum
You will spend more time reading code (yours and others') than writing it. Readable code:
- Is easier to debug
- Is easier for teammates to understand
- Is less likely to have hidden bugs
- Is easier to modify safely
PEP 8 — Python's Style Guide
PEP 8 is the official Python style guide. Here are the most important rules:
Naming Conventions
| What | Convention | Example |
|---|---|---|
| Variables | snake_case | user_name, total_count |
| Functions | snake_case | get_user(), calculate_total() |
| Constants | UPPER_SNAKE_CASE | MAX_RETRIES, BASE_URL |
| Classes | PascalCase | UserAccount, DatabaseError |
| Private (internal) | _leading_underscore | _internal_helper |
| Modules/files | lowercase or snake_case | utils.py, db_client.py |
# ✅ Good
MAX_CONNECTIONS = 10
def calculate_average(numbers):
...
class UserProfile:
...
# ❌ Bad
maxConn = 10 # camelCase for variable
UserEmail = "alice" # PascalCase for variable
CalculateAverage() # PascalCase for function
userprofile = ... # lowercase for class
Descriptive Names
# ❌ Cryptic
def calc(x, y, z):
return x * y + z
# ✅ Clear
def calculate_discounted_price(base_price, discount_rate, shipping_cost):
return base_price * (1 - discount_rate) + shipping_cost
Avoid single-letter names except for:
- Loop counters:
i,j,k - Math variables where it's conventional:
x,yin geometry - Lambda one-liners:
lambda x: x * 2
Whitespace and Spacing
# Around operators
x = 5 + 3 # ✅
x=5+3 # ❌
# After commas
print(a, b, c) # ✅
print(a,b,c) # ❌
# Around = in keyword arguments (no spaces)
print(end="") # ✅
print(end = "") # ❌
# Blank lines
# 2 blank lines between top-level definitions
def first_function():
...
def second_function():
...
# 1 blank line between methods inside a class
class MyClass:
def first(self):
...
def second(self):
...
Line Length
PEP 8 recommends 79 characters per line (many teams allow 99 or 120).
Break long lines using parentheses:
# Long function call — break inside parentheses
result = some_function(
argument_one,
argument_two,
argument_three,
)
# Long condition
if (
user.is_active
and user.has_permission("write")
and not user.is_banned
):
proceed()
# Long string
message = (
"This is a very long message that "
"spans multiple lines for readability."
)
Comments
Good comments explain why, not what (the code shows what):
# ❌ Useless comment (restates the code)
x = x + 1 # increment x by 1
# ✅ Useful comment (explains the reason)
x = x + 1 # offset by 1 because array is 0-indexed but display is 1-indexed
# ❌ Wrong comment (misleading!)
y = x * 2 # double the price (actually doubles the count!)
# ✅ Correct and useful
item_count = raw_count * 2 # multiply by 2: each container holds 2 items
Block comments (above the code they describe):
# Retry up to 3 times with exponential backoff.
# The API has a rate limit of 100 requests/minute.
for attempt in range(3):
...
Inline comments (same line, at least 2 spaces):
timeout = 30 # seconds; API SLA requires response within 25s
Docstrings
Docstrings document what a function does, its parameters, and return value:
def calculate_bmi(weight_kg: float, height_m: float) -> float:
"""
Calculate Body Mass Index (BMI).
Args:
weight_kg: Weight in kilograms.
height_m: Height in metres.
Returns:
BMI value as a float.
Raises:
ValueError: If height_m is zero or negative.
"""
if height_m <= 0:
raise ValueError(f"height_m must be positive, got {height_m}")
return weight_kg / (height_m ** 2)
Access docstrings with help():
help(calculate_bmi)
Type Hints
Type hints make code self-documenting:
# Without type hints
def greet(name):
return "Hello, " + name
# With type hints — clearer what goes in and comes out
def greet(name: str) -> str:
return "Hello, " + name
# More complex types
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
"""Returns username or None if not found."""
...
Auto-Formatting Tools
Don't spend time manually formatting — use tools:
# black: opinionated auto-formatter
pip install black
black src/
# ruff: fast linter + formatter
pip install ruff
ruff check src/
ruff format src/
# isort: sorts import statements
pip install isort
isort src/
Quick Reference
# Naming
variable_name = ... # snake_case
CONSTANT_NAME = ... # UPPER_SNAKE_CASE
def function_name(): ... # snake_case
class ClassName: ... # PascalCase
# Spacing
x = a + b # spaces around operators
func(a, b, c) # spaces after commas
func(key="value") # no spaces around = in kwargs
# Comments
# Explain why, not what
# Docstring
def fn(x: int) -> str:
"""Short description.
Args:
x: What x is.
Returns:
What the function returns.
"""
# Type hints
def fn(name: str, count: int = 1) -> list[str]:
...