When it genuinely nests
Nesting earns its place when the branches diverge — when the inner decision only makes sense inside the outer one, and each has its own alternative:
if age < 18:
return 0 if member else 5
return 8 if member else 12
Here "member" means something different in each branch. That is a real tree, not an accidental one.
Guard clauses flatten the rest
The most common nested shape is a series of refusals, each with an else:
if active:
if no_fines:
if available:
return "yes"
Four levels deep, and the success case — the thing the function is for — is buried furthest from the left margin, while every failure sits in an else far from the condition that caused it.
Inverted, each failure handles itself and leaves:
if not active: return "membership inactive"
if fines > 0: return "unpaid fines"
if not available: return "book is out"
return "yes"
Now every rule sits beside its own message, the happy path is the last line at zero indentation, and adding a rule is one line rather than another level. The page runs both over the same four cases and prints them side by side, because the point is that the behaviour is identical and only the shape changed.
elif is not nesting
if n > 100: ... elif n > 50: ... else: ...
An elif chain is one decision with several outcomes, all at the same indentation. Reaching for a nested if where an elif would do is how a flat choice becomes a staircase.
The rule of thumb
Two levels is normal. Three is worth a second look. Four almost always means either a set of guard clauses waiting to be inverted, or a block that wants to be its own function.