Break large Python files (>500 LOC) into smaller, well-organized modules with proper package structure. Use when a Python file is too large, monolithic, or needs refactoring...
Break large Python files into maintainable modules following Python best practices.
Choose a separation pattern:
By Responsibility (Recommended):
mypackage/
āāā __init__.py # Public API exports
āāā models.py # Data models/classes
āāā services.py # Business logic
āāā utils.py # Helper functions
āāā constants.py # Configuration
By Feature:
mypackage/
āāā __init__.py
āāā feature_a/
ā āāā __init__.py
ā āāā models.py
ā āāā logic.py
āāā feature_b/
By Layer (Domain-driven):
mypackage/
āāā __init__.py
āāā domain/ # Core models
āāā application/ # Use cases
āāā infrastructure/ # External deps
Present plan to user before proceeding.
mkdir mypackage
touch mypackage/__init__.py mypackage/models.py mypackage/services.py
Extract in dependency order:
In new modules:
# models.py
from .constants import DEFAULT_ROLE
from .utils import validate_email
In __init__.py (public API):
from .models import User, Product
from .services import create_user
__all__ = ['User', 'Product', 'create_user']
In external files:
# Before: from monolith import User
# After: from mypackage import User
ruff check mypackage/
mypy mypackage/
python -c "from mypackage import User"
pytest tests/
High Cohesion: Keep related code together
user_service.py not all_services.pyLow Coupling: Minimize dependencies
Single Responsibility: One clear purpose per module
Clear API: Use __init__.py to expose public interface
Option 1: Move shared code
# Create shared.py for common code
Option 2: TYPE_CHECKING
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .services import UserService # Only for type hints
Option 3: Late import
def process_user():
from .services import create_user # Import inside function
create_user()
Before (monolith.py - 800 lines):
DATABASE_URL = "sqlite:///./test.db"
class User:
def __init__(self, name):
self.name = name
def create_user(name):
return User(name)
app = FastAPI()
@app.get("/users")
def get_users():
return []
After:
api/
āāā __init__.py
āāā config.py # DATABASE_URL
āāā models.py # User class
āāā services.py # create_user
āāā routes.py # FastAPI routes
Import errors: Check __init__.py exports, verify relative imports (.module)
Circular imports: Use TYPE_CHECKING or late imports, or extract shared code
Tests failing: Update test imports to new package structure
For detailed examples, patterns, and troubleshooting, see references/detailed-guide.md.