| name | python-best-practices |
| description | Production-ready Python DOs and DON'Ts for engineers. Covers code quality, type hints, error handling, async patterns, testing, security, performance, logging, and data validation. Use when writing Python code that needs to be production-ready, reviewing Python code, refactoring legacy Python, or answering questions about Python best practices. Targets Python 3.12+. |
Python Best Practices (Production-Ready)
Production-grade DOs and DON'Ts for Python 3.12+.
Quick Reference
1. Code Quality & Style
Core Principle: Code is read more than written. Optimize for readability.
DO
def calculate_discounted_price(original_price: float, discount_rate: float) -> float:
return original_price * (1 - discount_rate)
@dataclass
class User:
name: str
email: str
created_at: datetime
def get_user(user_id: int) -> User | None:
if not user_id:
return None
return database.get_user(user_id)
with open("file.txt") as f:
content = f.read()
DON'T
def calc(a, b):
return a * b
user = {"nme": "Alice"}
f = open("file.txt")
content = f.read()
See references/clean-code.md
2. Type Hints
Core Principle: Type all public interfaces.
DO
def fetch_user(user_id: int) -> User | None: ...
type UserId = int
type JsonDict = dict[str, str | int | float]
def get_items[T](items: list[T]) -> list[T]: ...
class Renderable(Protocol):
def render(self) -> str: ...
DON'T
def process(data: Any) -> Any: ...
from typing import Union
def old(x: Union[str, int]): ...
See references/type-hints.md
3. Error Handling
Core Principle: Catch specific exceptions, never silent failures.
DO
try:
result = divide(a, b)
except ZeroDivisionError:
logger.error("Division by zero")
return None
class InsufficientFundsError(Exception):
def __init__(self, balance: float, required: float):
self.balance = balance
self.required = required
except FileNotFoundError as e:
raise ConfigError(f"Not found: {path}") from e
DON'T
try:
do_something()
except:
pass
try:
risky_operation()
except SomeError:
pass
See references/error-handling.md
4. Async/Await
Core Principle: Never block the event loop.
DO
async def fetch_user(user_id: int) -> User:
async with aiohttp.ClientSession() as session:
async with session.get(f"/users/{user_id}") as response:
return await response.json()
async def fetch_all(user_ids: list[int]) -> list[User]:
tasks = [fetch_user(id) for id in user_ids]
return await asyncio.gather(*tasks)
async def process_file(path: str) -> Result:
content = await asyncio.to_thread(read_file, path)
return process(content)
DON'T
async def bad():
time.sleep(5)
requests.get(url)
async def broken():
result = fetch_user(1)
return result
See references/async-patterns.md
5. Testing
Core Principle: Test behavior, not implementation.
DO
def test_user_creation_sets_email():
user = User(email="test@example.com")
assert user.email == "test@example.com"
@pytest.fixture
def user():
return User(email="test@example.com", balance=100)
@pytest.mark.parametrize("input,expected", [
("hello", "HELLO"), ("WORLD", "WORLD"), ("", ""),
])
def test_uppercase(input: str, expected: str):
assert input.upper() == expected
DON'T
def test_user_has_internal_dict():
assert user._data == {}
def test_create_user():
global created_user
created_user = User()
See references/testing.md
6. Security
Core Principle: Never trust input. Validate at boundaries.
DO
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
import secrets
token = secrets.token_urlsafe(32)
api_key = os.environ["API_KEY"]
DON'T
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
token = str(random.random())
API_KEY = "sk-abc123..."
result = eval(user_expression)
See references/security.md
7. Project Structure
Core Principle: Use src layout. Organize by feature.
DO
my-project/
├── src/mypackage/
│ ├── __init__.py
│ ├── core/service.py
│ ├── api/routes.py
│ └── models/user.py
├── tests/
│ └── test_service.py
├── pyproject.toml
└── README.md
DON'T
my-project/
├── mypackage.py # Single file for everything
├── tests.py # Tests mixed with source
└── utils/ # Junk drawer
See references/project-structure.md
8. Performance
Core Principle: Measure first. Optimize only proven bottlenecks.
DO
import cProfile
cProfile.run('my_function()')
def read_large_file(path: str):
with open(path) as f:
for line in f:
yield line.strip()
total = sum(item.price for item in items)
@lru_cache(maxsize=128)
def expensive_computation(n: int) -> int: ...
DON'T
result = ""
for s in strings:
result += s
if item in my_list:
See references/performance.md
9. Logging
Core Principle: Structured logs, appropriate levels.
DO
logger = logging.getLogger(__name__)
logger.info("User logged in", extra={"user_id": user.id})
import structlog
logger = structlog.get_logger()
logger.info("order_placed", order_id=123, total=99.99)
DON'T
print(f"User {user_id} logged in")
logger.info(f"Password: {password}")
logger.debug(f"Result: {expensive()}")
See references/logging.md
10. Data Validation
Core Principle: Validate at boundaries. Pydantic for external, dataclasses for internal.
DO
from pydantic import BaseModel, EmailStr
class UserCreate(BaseModel):
email: EmailStr
age: int
@dataclass
class User:
id: int
email: str
def process_request(data: dict) -> Response:
validated = UserCreate(**data)
return create_user(validated)
DON'T
def unsafe_process(data: dict):
email = data["email"]
config = json.load(f)
See references/data-validation.md
11. Code Review Checklist
Blockers (Must Fix)
Improvements (Nice to Have)
See references/code-review.md
Reference Files Index
| File | Content |
|---|
references/clean-code.md | Naming, functions, dataclasses |
references/type-hints.md | Generics, protocols, modern syntax |
references/error-handling.md | Custom exceptions, cleanup |
references/async-patterns.md | Event loop, TaskGroup, patterns |
references/testing.md | Pytest, fixtures, mocking |
references/security.md | Input validation, crypto, OWASP |
references/project-structure.md | Src layout, organization |
references/performance.md | Profiling, optimization |
references/logging.md | Structured logging, levels |
references/data-validation.md | Pydantic, dataclasses |
references/code-review.md | Full checklist |
references/anti-patterns.md | Common mistakes |