Use type hints and comprehensive documentation for better code clarity and maintainability.
Always use type hints for function parameters, return values, and class attributes to improve code clarity and enable better IDE support.
from typing import Any
# ✅ Good type annotations
def process_user_data(
username: str,
age: int,
is_active: bool = True
) -> dict[str, Any]:
"""Process user data and return formatted result."""
return {
"username": username.lower(),
"age": age,
"is_active": is_active,
"processed_at": datetime.now()
}
# ✅ Class with type hints
class DatabaseConnection:
"""Handle database connections with proper type hints."""
def __init__(self, host: str, port: int, database: str):
self.host: str = host
self.port: int = port
self.database: str = database
self.connection: Connection | None = None
def connect(self) -> bool:
"""Establish database connection."""
try:
# Connection logic
return True
except ConnectionError:
return False
def execute_query(self, query: str, params: list[Any] = None) -> list[dict]:
"""Execute query and return results."""
if params is None:
params = []
# Query execution logic
return [] from typing import Any
from collections.abc import Callable
# ✅ Generic collections
def process_items(items: list[str]) -> dict[str, int]:
"""Count character length for each item."""
return {item: len(item) for item in items}
def filter_users(
users: list[dict[str, Any]],
filter_func: Callable[[dict], bool]
) -> list[dict[str, Any]]:
"""Filter users based on provided function."""
return [user for user in users if filter_func(user)]
# ✅ Optional and Union types
def get_user_by_id(user_id: int) -> dict[str, Any] | None:
"""Get user by ID, return None if not found."""
# Database lookup logic
return None # or user dict
def parse_input(value: str | int | float) -> str:
"""Convert various input types to string."""
return str(value)
# ✅ Tuple types
def get_coordinates() -> tuple[float, float]:
"""Return latitude and longitude coordinates."""
return (40.7128, -74.0060)
def get_user_info() -> tuple[str, int, bool]:
"""Return username, age, and active status."""
return ("john_doe", 30, True) from typing import TypedDict, NewType
from datetime import datetime
# ✅ Custom type aliases
UserId = NewType('UserId', int)
EmailAddress = NewType('EmailAddress', str)
# ✅ TypedDict for structured dictionaries
class UserData(TypedDict):
id: UserId
username: str
email: EmailAddress
created_at: datetime
is_active: bool
class ApiResponse(TypedDict):
success: bool
data: UserData | None
error: str | None
# ✅ Using custom types
def create_user(
username: str,
email: EmailAddress
) -> UserData:
"""Create a new user with proper type structure."""
return UserData(
id=UserId(generate_id()),
username=username,
email=email,
created_at=datetime.now(),
is_active=True
)
def send_email(user_id: UserId, email: EmailAddress, message: str) -> bool:
"""Send email to specific user."""
# Email sending logic
return True Use Google-style or NumPy-style docstrings for comprehensive function and class documentation.
from typing import Any
def authenticate_user(username: str, password: str, remember_me: bool = False) -> dict[str, Any]:
"""Authenticate user with provided credentials.
This function verifies user credentials against the database and returns
authentication result with user information if successful.
Args:
username: The username for authentication. Must be a non-empty string.
password: The user's password. Will be hashed before comparison.
remember_me: Whether to create a persistent session. Defaults to False.
Returns:
A dictionary containing authentication result:
{
'success': bool,
'user': dict or None,
'token': str or None,
'expires_at': datetime or None
}
Raises:
ValueError: If username or password is empty.
DatabaseError: If database connection fails.
Example:
>>> result = authenticate_user("john_doe", "secure_password")
>>> if result['success']:
... print(f"Welcome, {result['user']['name']}!")
"""
if not username or not password:
raise ValueError("Username and password cannot be empty")
# Authentication logic here
return {
'success': True,
'user': {'id': 1, 'name': 'John Doe'},
'token': 'jwt_token_here',
'expires_at': datetime.now() + timedelta(hours=24)
} class PaymentProcessor:
"""Process various payment methods for e-commerce transactions.
This class handles payment processing for multiple payment providers
including credit cards, PayPal, and bank transfers. It provides a
unified interface for payment operations with proper error handling
and logging.
Attributes:
api_key: The API key for payment provider authentication.
provider: The payment provider name (e.g., 'stripe', 'paypal').
sandbox_mode: Whether to use sandbox/test mode for payments.
Example:
>>> processor = PaymentProcessor(api_key="key123", provider="stripe")
>>> result = processor.process_payment(amount=29.99, method="credit_card")
>>> if result.success:
... print(f"Payment processed: {result.transaction_id}")
"""
def __init__(self, api_key: str, provider: str, sandbox_mode: bool = False):
"""Initialize payment processor.
Args:
api_key: API key for payment provider authentication.
provider: Payment provider name ('stripe', 'paypal', 'square').
sandbox_mode: Use sandbox mode for testing. Defaults to False.
Raises:
ValueError: If api_key is empty or provider is not supported.
"""
if not api_key:
raise ValueError("API key cannot be empty")
supported_providers = ['stripe', 'paypal', 'square']
if provider not in supported_providers:
raise ValueError(f"Provider must be one of: {supported_providers}")
self.api_key = api_key
self.provider = provider
self.sandbox_mode = sandbox_mode
self._session = self._create_session()
def process_payment(
self,
amount: float,
currency: str = "USD",
method: str = "credit_card"
) -> PaymentResult:
"""Process a payment transaction.
Args:
amount: Payment amount in the specified currency.
currency: Currency code (ISO 4217). Defaults to "USD".
method: Payment method ('credit_card', 'paypal', 'bank_transfer').
Returns:
PaymentResult object containing transaction details and status.
Raises:
PaymentError: If payment processing fails.
ValueError: If amount is negative or currency is invalid.
"""
# Payment processing logic
pass Use mypy for static type checking to catch type-related errors before runtime.
# pyproject.toml
[tool.mypy]
python_version = "3.12"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
# Per-module options
[[tool.mypy.overrides]]
module = "tests.*"
ignore_errors = true
[[tool.mypy.overrides]]
module = "third_party_library.*"
ignore_missing_imports = true # type: ignore sparingly and with commentsfrom typing import Protocol, runtime_checkable
from abc import ABC, abstractmethod
# ✅ Protocol for duck typing
@runtime_checkable
class Drawable(Protocol):
"""Protocol for drawable objects."""
def draw(self) -> None:
"""Draw the object."""
...
def render_object(obj: Drawable) -> None:
"""Render any drawable object."""
obj.draw()
# ✅ Abstract base class
class DataProcessor(ABC):
"""Abstract base class for data processors."""
@abstractmethod
def process(self, data: list[dict]) -> list[dict]:
"""Process data and return results."""
pass
def validate_data(self, data: list[dict]) -> bool:
"""Validate input data format."""
return all(isinstance(item, dict) for item in data)
# ✅ Generic class
from typing import Generic, TypeVar
T = TypeVar('T')
class Repository(Generic[T]):
"""Generic repository pattern."""
def __init__(self, model_class: type[T]):
self.model_class = model_class
self._items: list[T] = []
def add(self, item: T) -> None:
"""Add item to repository."""
self._items.append(item)
def find_by_id(self, id: int) -> T | None:
"""Find item by ID."""
# Search logic
return None
def get_all(self) -> list[T]:
"""Get all items."""
return self._items.copy()
# Usage
user_repo = Repository[User](User)
product_repo = Repository[Product](Product)