atexit registers functions that run when the interpreter terminates normally. It fits small, local cleanup such as removing a temporary marker or emitting one final metric.
Practical example
import atexit
from pathlib import Path
temporary = Path("job.lock")
temporary.touch()
@atexit.register
def remove_lock() -> None:
temporary.unlink(missing_ok=True)
print("lock removed")
Order and arguments
Functions run in reverse registration order. register() accepts arguments too, but a short function without fragile dependencies is more predictable during shutdown.
What not to delegate
Do not make a handler the only way to save important data. The process may receive SIGKILL, hit a fatal failure, or stop before completion. Persist progress atomically during normal work.
Prefer a context manager
When a resource has a clear scope, with closes files, connections, and locks at the right point, including after exceptions. Keep atexit for resources tied to the whole process lifetime.
Keep learning
Strengthen the foundation with error handling in Python. The official Python documentation, accessed July 22, 2026, documents the API, limitations, and version differences.