DevHireLab
Tutorials
BootcampProblemsCode SimulatorAI InterviewSoonContact
DevHireLab
Tutorials
BootcampProblemsCode SimulatorAI InterviewSoonContact
Getting Started
01
What is Python and Why Learn It in 2026
02
Installing Python on Windows, Mac, and Linux
03
Setting up VS Code / PyCharm for Python
04
Understanding the Python Interpreter and REPL
05
Writing and Running Your First Python Program
06
Python Syntax and Indentation Rules
Variables and Data Types
01
Variables and Naming Conventions in Python
02
Numbers in Python (int, float, complex)
03
Strings and String Methods in Python
04
Booleans in Python
05
Type Conversion / Casting in Python
06
Understanding the None Type in Python
Operators
01
Arithmetic Operators in Python
02
Comparison Operators in Python
03
Logical Operators in Python
04
Assignment Operators in Python
05
Bitwise Operators in Python
06
Identity (is) and Membership (in) Operators
07
Walrus Operator (:=) in Python
Input, Output & Strings
01
input() and print() Functions in Python
02
f-strings and String Formatting in Python
03
String Slicing and Indexing in Python
04
Common String Methods (split, join, strip, replace)
05
Escape Characters in Python Strings
Control Flow
01
if, elif, else Statements in Python
02
Nested Conditionals in Python
03
for Loops in Python
04
while Loops in Python
05
break, continue, and pass Statements
06
Loop with else Clause in Python
07
match-case (Structural Pattern Matching)
Data Structures
01
Python Lists: Creation, Indexing, Slicing, Methods
02
Python Tuples and Immutability
03
Python Sets and Set Operations
04
Python Dictionaries: Keys, Values, and Methods
05
List Comprehensions in Python
06
Dictionary & Set Comprehensions in Python
07
Working with Nested Lists and Dictionaries
Functions
01
Defining and Calling Functions in Python
02
Function Arguments: Positional, Keyword, Default
03
*args and **kwargs in Python
04
Return Statements in Python Functions
05
Lambda Functions in Python
06
Recursion in Python
07
Variable Scope: Local, Global, Nonlocal
08
Docstrings and Function Annotations
Functional Programming Basics
01
map(), filter(), and reduce() in Python
02
Closures in Python Explained
03
Python Decorators: Basic to Advanced
04
Generators and yield in Python
Object-Oriented Programming (OOP)
01
Classes and Objects in Python
02
The init Constructor in Python
03
Instance vs Class Variables in Python
04
Inheritance in Python (Single, Multiple, Multilevel)
05
Polymorphism in Python
06
Encapsulation in Python
07
Abstraction in Python with the abc Module
08
Magic/Dunder Methods in Python
09
Static and Class Methods in Python
10
The @property Decorator in Python
11
Python Dataclasses Explained
Error Handling
01
try, except, finally in Python
02
Handling Multiple Exceptions in Python
03
Raising Custom Exceptions in Python
04
Understanding Python's Exception Hierarchy
05
Assertions in Python
File Handling
01
Reading and Writing Text Files in Python
02
Working with the with Statement in Python
03
Working with CSV Files in Python
04
Working with JSON Files in Python
05
Working with Directories (os, pathlib) in Python
Modules and Packages
01
Importing Built-in Modules in Python
02
Creating Your Own Modules in Python
03
Understanding Packages and init.py
04
Python Standard Library Overview
05
Installing Packages with pip
Advanced Core Concepts
01
Iterators and Iterables in Python
02
Context Managers in Python (with, contextlib)
03
Multithreading Basics in Python
04
Multiprocessing Basics in Python
05
Asyncio Basics: async/await in Python
06
Memory Management and Garbage Collection in Python
07
Type Hints in Python (typing module)

Nested Conditionals in Python

Some decisions in code genuinely depend on another decision already being true. python nested if statements are how you express that — an if living inside another if, checking a second condition that only makes sense once the first has already passed. This article covers how nesting works, when it's the right tool, and — just as important — when it isn't.

What Are Nested Conditionals?

A nested conditional is simply an if statement placed inside another if (or else) block.

number = 25

if number > 10:
    if number > 20:
        print("Greater than 20")

The inner if number > 20: only gets evaluated at all if the outer condition, number > 10, was already True. Nested conditionals exist for exactly this situation: a second check that genuinely only makes sense after a first one has already been satisfied.

How Nesting Works: Indentation and Flow

Each level adds indentation

As covered in the earlier article on Python syntax, each nested block requires its own additional level of indentation — the deeper the nesting, the further right the code shifts:

number = 25

if number > 10:          # first level
    if number > 20:        # second level
        print("Greater than 20")
The outer condition acts as a gatekeeper

This is the core idea to hold onto: the outer if controls whether the inner one even gets a chance to run. If the outer condition is False, Python never evaluates the inner block at all — it's skipped entirely, exactly the same way a single unmatched if gets skipped.

Practical example: age and license status
age = 20
has_license = True

if age >= 18:
    if has_license:
        print("You can drive")
    else:
        print("You need a license first")
else:
    print("You're too young to drive")

Notice the structure here: the license check only happens inside the branch where age is already confirmed to be 18 or older. There's no reason to even ask about a license if the person is underage — the outer condition correctly gatekeeps the inner one.

3. Nested if-else and Multiple Levels

Combining if-else at each level

You can pair if/else at every level of nesting, not just the outer one, to express more complete branching logic:

age = 16
is_member = True

if age >= 18:
    if is_member:
        price = 8
    else:
        price = 12
else:
    if is_member:
        price = 5
    else:
        price = 7

print(price)   # 5

This handles all four combinations of age and membership status, with each branch reachable only through its specific combination of outer and inner conditions.

Nesting elif chains inside an outer if

You can also nest a full elif chain inside an outer if, useful when an entire category of logic should only run under some outer gatekeeping condition:

score = 78
attempted = True

if attempted:
    if score >= 90:
        grade = "A"
    elif score >= 80:
        grade = "B"
    elif score >= 70:
        grade = "C"
    else:
        grade = "F"
else:
    grade = "Incomplete"

print(grade)   # C

Here, the entire grading elif chain only matters if the outer attempted check passed — otherwise, none of the score thresholds are even relevant.

How deep nesting can go — and why it usually shouldn't

Technically, Python doesn't impose any real practical limit on how many levels deep you can nest conditionals. Four, five, six levels — it'll run. But each additional level makes the code measurably harder to read and mentally trace, and it's rarely necessary. Section 5 covers concrete ways to avoid it.

Nested Conditionals vs. Chained Conditionals (elif)

The key distinction

This is the single most useful thing to internalize from this article: elif chains are for mutually exclusive, either/or scenarios — exactly one branch should run, and the branches represent alternative possibilities for the same question. Nesting is for conditions that genuinely depend on one another — the inner question doesn't even make sense to ask unless the outer one was already answered a certain way.

Side-by-side example
# elif — mutually exclusive alternatives answering the same question ("what grade?")
score = 85

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
else:
    grade = "F"
# Nesting — the inner question depends on the outer one
age = 20
has_license = True

if age >= 18:            # first question: are they even old enough?
    if has_license:         # second question: only relevant if they are
        print("Can drive")

Trying to force the license example into an elif chain wouldn't make sense, because "has a license" and "is under 18" aren't alternative answers to the same question — they're two separate, dependent facts. Conversely, forcing the grading example into nested if statements would work but add unnecessary indentation for what's really a single flat decision.

Common mistake: nesting where and/or or elif would be clearer

A frequent beginner habit is reaching for nested if statements when a combined condition using and or or — covered in the earlier logical operators article — would say the same thing more directly:

# Unnecessarily nested
if age >= 18:
    if has_license:
        print("Can drive")

# Flatter and equally correct
if age >= 18 and has_license:
    print("Can drive")

Both versions behave identically. The flattened version is simply easier to read at a glance, since there's no need to mentally track two separate indentation levels to understand that both conditions are required.

Best Practices for Readable Nested Code

Guideline: avoid nesting more than 2–3 levels deep

As a practical rule of thumb, if you find yourself nesting more than two or three levels deep, treat that as a signal to refactor rather than push forward. Deeply nested code becomes genuinely hard to follow — by the time you're four levels in, tracking which combination of outer conditions got you there requires real mental effort from anyone reading it.

Alternative: combining conditions with and/or

As shown above, this is the simplest fix when nested conditions don't actually depend on separate, distinct questions — they're really just several requirements for the same single decision.

Alternative: early returns and guard clauses

Inside a function, one of the most effective ways to flatten nested conditionals is the "guard clause" pattern: check for disqualifying conditions early, return immediately if they apply, and let the rest of the function assume the happy path.

# Before: deeply nested
def check_eligibility(age, has_license, has_insurance):
    if age >= 18:
        if has_license:
            if has_insurance:
                return "Eligible to drive"
            else:
                return "Needs insurance"
        else:
            return "Needs a license"
    else:
        return "Too young"
# After: flattened with guard clauses
def check_eligibility(age, has_license, has_insurance):
    if age < 18:
        return "Too young"
    if not has_license:
        return "Needs a license"
    if not has_insurance:
        return "Needs insurance"
    return "Eligible to drive"

Both versions produce identical results, but the second one never nests more than one level deep. Each guard clause handles exactly one disqualifying condition and exits immediately, so by the time you reach the final return, every prerequisite has already been confirmed — there's no need to keep tracking multiple layers of "but only if the outer condition was also true."

This pattern is worth adopting early. It won't fit every situation — some logic genuinely is hierarchical, like the age/license/membership pricing example earlier — but for the common case of "check several disqualifying conditions before proceeding," guard clauses consistently produce flatter, more readable code than deep nesting.

PREVIOUSNEXT LESSON