PEP 1 explains what PEPs are and how they work.
PEP 8 was written by Guido van Rossum (Pythonβs creator) and others, and became the canonical style guide.
Other famous PEPs:
PEP 20 β The Zen of Python (import this)
PEP 484 β Type hints
PEP 572 β The walrus operator (:=)
A practical, modern guide to writing clean, professional Python code.
Covers PEP 8, industry standards (2025), and rare pitfalls every dev should know.
- Use 4 spaces per indentation level (never tabs).
- Max line length: 88 chars (modern consensus, e.g.,
blackformatter).
def my_function():
for i in range(5):
print(i) # β
Clean indentation- 2 blank lines before top-level functions/classes.
- 1 blank line between methods in a class.
class MyClass:
def method_one(self):
pass
def method_two(self):
pass- One import per line.
- Order: standard library β third-party β local.
- Use absolute imports, relative only inside packages.
- Avoid wildcard imports.
import os
import sys
import requests
from myproject import utils- Variables / functions β
lower_case_with_underscores - Classes β
CapWords - Constants β
UPPER_CASE_WITH_UNDERSCORES - Private/internal β
_leading_underscore
MAX_SIZE = 100
def calculate_area(radius):
return 3.14 * radius * radius
class Circle:
def __init__(self, radius):
self._radius = radiusβ Correct vs β Wrong
x = y + z # β
x=y+z # β
func(a, b, c) # β
func(a , b , c ) # β
my_list = [1, 2, 3] # β
my_list = [ 1 ,2 , 3 ] # β- Use
"""triple quotes"""for docstrings. - First line = short summary.
- Comments explain why, not what.
def add(x: int, y: int) -> int:
"""Return the sum of x and y."""
return x + y- Break long arg lists after
(.
def my_function(param1, param2,
param3, param4):
pass- Donβt compare to
True/False.
if my_list: # β
if len(my_list) != 0: # β
if my_list == True: # βif x == 4: print(x, y) # β
if x == 4 : print(x , y ) # β- Readability > Cleverness.
- Consistency matters.
- Follow The Zen of Python (
import this).
- Donβt align variables artificially.
x = 1
y = 2
long_variable_name = 3 # β
- Choose
'single'or"double"consistently. - Use
"""triple"""for docstrings.
- Donβt use unnecessary parentheses.
- No semicolons.
- No multiple statements per line.
if x and y: # β
if (x and y): # βmy_list = [
1,
2,
3,
]- Use
isforNone,==for values.
if foo is None: # β
if foo == None: # β- Use
is notinstead ofnot ... is. - Use
.startswith()/.endswith(). - Prefer
infor membership.
if name.startswith("Mr."): # β
- Always use type hints in new code.
def greet(name: str) -> str:
return f"Hello {name}"count: int = 0- Use f-strings, not
format()or%.
name = "Alice"
print(f"Hello {name}!") # β
- Prefer
pathliboveros.path.
from pathlib import Path
data_dir = Path("data")
print(data_dir.exists())- Prefer
enumerate()andzip()to manual indexing.
for i, value in enumerate(my_list):
print(i, value)- Always use
withfor file/connection handling.
with open("file.txt") as f:
data = f.read()- Prefer
@dataclassfor simple data holders.
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int- Use
blackfor formatting. - Use
rufforflake8for linting. - Use
mypyfor type checking.
-
Mutable default args:
def bad(x, items=[]): # β Dangerous! items.append(x) return items def good(x, items=None): # β if items is None: items = [] items.append(x) return items
-
Late binding closures:
funcs = [lambda: i for i in range(3)] print([f() for f in funcs]) # β [2, 2, 2] funcs = [lambda i=i: i for i in range(3)] print([f() for f in funcs]) # β [0, 1, 2]
-
Floating-point precision:
0.1 + 0.2 == 0.3 # β False
-
Chained mutable defaults (dict/set pitfalls).
- Be consistent with the existing project.
- Prioritize readability.
- Automate checks with pre-commit hooks.
PEP 8 isnβt about perfection β itβs about consistency, clarity, and collaboration. In 2025, teams standardize with:
- black (formatting)
- ruff/flake8 (linting)
- mypy (type safety)
Write Python thatβs:
- Readable
- Predictable
- Maintainable
PEP = Python Enhancement Proposal.
Itβs like a βrulebook pageβ or βproposalβ for Python
Some PEPs are rules for writing code (style).
Some are new features.
Some are about packaging/distribution.
This doc explains the most useful PEPs simply, with examples.
The grammar rules for Python code.
β Example:
def add(x: int, y: int) -> int:
return x + yβ Example:
def add(x,y):return x+yMain ideas:
- 4 spaces for indentation.
- Max ~88 chars per line.
- Clear names (
total_pricenottp). - Add spaces around operators (
x = y + z).
Pythonβs philosophy. See it by typing:
import thisKey rules:
- Explicit is better than implicit β Be clear.
- Simple is better than complex β Donβt overcomplicate.
- Readability counts β Code should be easy to read.
How to write docstrings (function/class comments).
β Example:
def greet(name: str) -> str:
"""Return a greeting message for the given name."""
return f"Hello {name}"Introduced the iterator protocol β made for loops powerful.
for letter in "hello":
print(letter)Introduced context managers. Automatically handles closing files, connections, etc.
β Example:
with open("file.txt") as f:
data = f.read()β Example:
f = open("file.txt")
data = f.read()
f.close() # you must remember thisAdded type hints β makes code easier to read and check.
def add(x: int, y: int) -> int:
return x + yLets you add type hints to variables.
count: int = 0Introduced the walrus operator. Assign a value inside an expression.
β Example:
while (line := input("Type: ")) != "quit":
print(line)Use built-in types directly for typing.
β Example:
def get_numbers() -> list[int]:
return [1, 2, 3]β Old way:
from typing import List
def get_numbers() -> List[int]:
return [1, 2, 3]Simpler syntax for multiple possible types.
β Example:
def square(x: int | float) -> float:
return x * xβ Old way:
from typing import Union
def square(x: Union[int, float]) -> float:
return x * x- PEP 563 (postponed evaluation) β annotations were stored as strings.
- PEP 649 β newer solution, keeps them efficient without breaking tools.
Result: type hints are fast and memory-friendly in new Python versions.
Lets you assign inside conditions.
if (n := len([1, 2, 3])) > 2:
print(f"List has {n} items")Adds strict=True option. Raises error if zipped lists arenβt same length.
zip([1, 2], [3], strict=True) # β ErrorIntroduced match / case (Python 3.10).
Like switch in other languages, but more powerful.
β Example:
def handle(value):
match value:
case 0:
return "zero"
case [x, y]:
return f"pair: {x}, {y}"
case _:
return "something else"Handle multiple errors together.
try:
...
except* ValueError as e:
print("value error")You can now use f-strings inside more places, like docstrings.
These affect how Python projects are shared and installed:
- PEP 427 β Wheels β
.whlfiles = faster installs. - PEP 440 β Versioning β standard rules for versions (
1.0.0,2.1.3b1). - PEP 518 β
pyproject.tomlβ modern project config. - PEP 621 β Metadata in TOML β standard way to write project info.
Example pyproject.toml:
[project]
name = "myapp"
version = "1.0.0"
dependencies = ["requests"]-
PEP 572 β Walrus Operator (again, because itβs easy to misuse).
-
PEP 622 β Pattern Matching can be tricky:
- Order matters (like if/elif).
_means βanythingβ.
| PEP | What it does | Why it matters | |
|---|---|---|---|
| 8 | Style guide | Code looks clean & consistent | |
| 20 | Zen of Python | Philosophy: keep it simple, readable | |
| 257 | Docstrings | Standard way to explain code | |
| 234 | Iterators | Makes for loops powerful |
|
| 343 | with |
Auto-close files/resources | |
| 484 | Type hints | Easier to read/check functions | |
| 526 | Variable annotations | Type hints for variables | |
| 572 | Walrus operator | Assign inside expressions | |
| 585 | Built-in generics | Use list[int] instead of List[int] |
|
| 604 | Union types | Use `int | strinstead ofUnion` |
| 622 | Match/case | Pattern matching (Python 3.10) | |
| 654 | Exception groups | Handle multiple errors | |
| 427 | Wheel format | Faster package installs | |
| 518 | pyproject.toml | Standard project config | |
| 621 | Metadata in TOML | Project info in one place |
- PEP 8 + PEP 20 = how to write and think in Python.
- Type hints (PEP 484, 585, 604) = modern standard (2025).
- Packaging PEPs (518, 621) = all new projects should use
pyproject.toml. - Pattern matching (PEP 622) = powerful but use carefully.
- Linters + formatters (black, ruff, mypy) β enforce these rules automatically.
Python keeps evolving, but these PEPs are the ones youβll use every day.