Code Formatting
Code formatting is the part of code style you can automate. Consistent spacing, line breaks and blank lines, organized imports, and other formatting practices make it easier to scan a Python file, spot what changed in a diff, and understand code at a glance.
Rather than debating whitespace and wrapping in reviews, you can rely on automated tools to enforce consistency.
Here are some best practices that you can apply when dealing with code formatting:
- Format code automatically. Use a dedicated code formatter like Black or Ruff’s formatter to apply consistent formatting across a project. This frees reviewers to focus on correctness, design, and behavior.
- Use a linter to catch style and quality issues. Linters like Ruff, flake8, and Pylint can flag unused imports, inconsistent naming, and other issues that reduce readability or signal bugs.
- Run formatting tools as part of your workflow. Add formatters to pre-commit hooks and CI so every change is formatted the same way, regardless of who authored it. Configure your code editor or IDE to automatically format the code on save when supported.
To illustrate how applying some of these best practices can improve your code, consider the following example:
🔴 Avoid this:
users.py
import os,sys
import json
from app.utils import normalize_email
import requests
from datetime import datetime
from app.config import load_config
def fetch_user(email,token):
headers={"Authorization":f"Bearer {token}","Content-Type":"application/json"}
r=requests.get("https://api.example.com/v1/users",params={"email":normalize_email(email)},headers=headers,timeout=10)
if r.status_code!=200:raise RuntimeError(f"Bad status {r.status_code}")
return r.json()
def main():
print(sys.version)
cfg=load_config();user=fetch_user(cfg["email"],cfg["token"])
print(user)
if __name__=="__main__":
main()
This code works, but the imports are out of order and mixed together without grouping. The file also crams multiple statements onto single lines and omits the blank lines that help readers see where one logical section ends and the next begins.
✅ Favor this:
users.py
import sys
import requests
from app.config import load_config
from app.utils import normalize_email
def fetch_user(email, token):
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
response = requests.get(
"https://api.example.com/v1/users",
params={"email": normalize_email(email)},
headers=headers,
timeout=10,
)
if response.status_code != 200:
raise RuntimeError(f"Bad status {response.status_code}")
return response.json()
def main():
print(sys.version)
config = load_config()
user = fetch_user(config["email"], config["token"])
print(user)
if __name__ == "__main__":
main()
Now, the imports are grouped according to PEP 8 guidelines—standard library, third-party, and local imports—with blank lines separating each group. Spacing around operators and blank lines between top-level definitions make the file quicker to scan.
A code formatter like Black or Ruff’s formatter can apply most formatting rules automatically, so you don’t have to think about every small detail. Formatters are especially useful for teams because they reduce noisy diffs and keep reviews focused on behavior rather than style.
Related Resources
Tutorial
Ruff: A Modern Python Linter for Error-Free and Maintainable Code
Ruff is an extremely fast, modern linter with a simple interface, making it straightforward to use. It also aims to be a drop-in replacement for other linting and formatting tools, like Pylint, isort, and Black. It's no surprise it's quickly becoming one of the most popular Python linters.
For additional information on related topics, take a look at the following resources:
- Modern Python Linting With Ruff (Course)
- Ruff: A Modern Python Linter (Quiz)