You’ve built a beautiful CLI with Typer. It’s got great commands, helpful documentation, and does exactly what you need. There’s just one problem: running cli --help takes 3 seconds. Tab completion feels sluggish.
The culprit? Eager imports loading heavy dependencies before they’re needed.
Let’s fix that.
The Problem: Death by a Thousand Imports
Here’s a common pattern I see in CLI applications:
# ❌ BAD: All imports at the top
import typer
import os
import sys
import torch
import transformers
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from PIL import Image
app = typer.Typer()
@app.command()
def predict(image_path: str):
"""Run ML prediction on an image."""
model = torch.load("model.pt")
img = Image.open(image_path)
# ... prediction logic
@app.command()
def train(data_path: str):
"""Train a new model."""
df = pd.read_csv(data_path)
# ... training logic
if __name__ == "__main__":
app()When you run cli --help, Python dutifully loads PyTorch, Transformers, Pandas, NumPy, scikit-learn, and Pillow before showing you the help text. That can easily take 2-5 seconds on a cold start. To make matters worse, all of this happens during tab-completion too.
The Solution: Lazy Loading
The fix is simple: only import what you need, when you need it.
# ✅ GOOD: Lazy imports inside functions
import typer
app = typer.Typer()
@app.command()
def predict(image_path: str):
"""Run ML prediction on an image."""
# Import only when this command is actually run
import torch
from PIL import Image
model = torch.load("model.pt")
img = Image.open(image_path)
# ... prediction logic
@app.command()
def train(data_path: str):
"""Train a new model."""
import pandas as pd
df = pd.read_csv(data_path)
# ... training logic
if __name__ == "__main__":
app()Now cli --help loads in milliseconds. Tab completion is instant. Your users are happy.
Be Selective: Not All Imports Are Equal
Not every import needs to be lazy. Some modules load instantly, and putting them inside functions just adds clutter:
# ✅ Fast imports: Keep at the top
import os
import sys
import json
import re
import pathlib
from typing import Optional, List
import typer
# ❌ Slow imports: Move inside functions
# import torch
# import transformers
# import pandas
# import numpy
# import PIL
# import cv2
# import tensorflowRule of thumb: If it’s in the Python standard library or is a lightweight pure-Python package, it’s probably fine at the top. If it’s a heavy data science, ML, or image processing library, lazy load it. I often experiment a bit to find which packages are slow and selectively lazy-load those.
Measuring the Impact
Don’t guess—measure! Use the time command to see the difference:
# Before optimization
$ time cli --help
real 0m3.247s
user 0m2.891s
sys 0m0.342s
# After optimization
$ time cli --help
real 0m0.124s
user 0m0.098s
sys 0m0.024sThat’s a 26× speedup! For tab completion, which calls your CLI repeatedly, this difference is make-or-break.
