Python Lesson 6: Conditionals — if, elif, else, Truthiness & Nested Logic
Chapters: 0:00 Lesson 6: Making Decisions in Code 0:15 The Everyday Idea 0:29 Key Words, In Plain English 0:44 The Simple if 1:01 Adding else: The Other Road 1:14 elif: More Than Two Choices 1:32 Order Matters 1:49 Truthiness: The Sneaky Superpower 2:10 What Counts as Falsy 2:29 Mistake: = Instead of == 2:49 Nested Conditions 3:09 Nesting vs Combining with and 3:30 and, or, not: Quick Combos 3:47 Recap: You Can Branch Now Learn how Python makes decisions. This lesson walks through if, elif, and else from plain-English logic to real branching code. You'll master why order matters, the sneaky power of truthiness (and what counts as falsy), the classic = vs == mistake, and when to nest conditions versus combining them with and/or/not. By the end, your programs can choose their own path. #Python #LearnToCode #Programming #Coding #PythonBeginners
Introduction
Every program you've written so far has run the same way: top to bottom, one line after another, like a train stuck on a single track. That's fine for simple scripts, but it's not how real software works. Real programs need to react — to user input, to sensor readings, to whatever state the system happens to be in at the moment. That reaction is built entirely on conditionals.
If you've ever looked at an interview problem and thought "I know the logic, I just don't know how to structure the checks," conditionals are usually the missing piece. Interviewers care about this because sloppy branching is one of the most common sources of bugs in real code — an elif in the wrong order, a = where a == should be, a deeply nested mess that nobody can read six months later. Getting comfortable with if, elif, else, and Python's truthiness rules isn't just a beginner milestone. It's the foundation every algorithm you'll ever write sits on top of.
By the end of this lesson, you'll understand not just the syntax but the reasoning behind it — why order matters, why Python lets you use almost any value as a yes/no answer, and when nesting conditions is the right call versus when it's just clutter.
Problem Overview
At its core, a conditional is a piece of code that only runs when something is true. Think about your morning routine: if it's raining, you grab an umbrella. Otherwise, you don't. That's it — that's a conditional in plain English.
Python gives you three tools to express this:
if— run this block only if the condition is true.elif— short for "else if." Check another condition, but only if the previous ones failed.else— the catch-all. Runs when nothing above it was true.
Underneath all of this sits a concept called a boolean — a value that's either True or False. Every condition you write eventually boils down to one of these two values, and Python decides which branch to run based on it.
Example
Let's start with the simplest possible version:
temp = 35
if temp > 30:
print("It's hot!")
Here, temp > 30 is the condition — a question that resolves to True or False. Since 35 > 30 is True, the indented line runs and prints It's hot!. Notice two things: the colon at the end of the if line, and the indentation on the next line. That indentation is Python's way of saying "this code belongs inside the if."
Now let's add an alternative path:
age = 15
if age >= 18:
print("Adult")
else:
print("Minor")
Since age is 15, the condition age >= 18 is False, so Python skips straight to else and prints Minor. Only one branch ever runs — never both, never neither.
Finally, let's handle more than two outcomes with elif:
score = 82
if score >= 90:
print("A")
elif score >= 80:
print("B")
elif score >= 70:
print("C")
else:
print("F")
Python checks each condition from top to bottom and stops at the first one that's True. Since score is 82, it fails the >= 90 check, passes the >= 80 check, prints B, and never even looks at the remaining branches.
Intuition
Here's the part experienced engineers internalize but rarely explain out loud: conditionals are just a sequence of gates, checked in order, and the first gate that opens wins.
That single fact explains almost every bug you'll ever hit with if/elif/else. Consider this broken version of the grading example:
score = 95
if score >= 70:
print("C")
elif score >= 90:
print("A")
score is 95, which clearly deserves an A. But because the loose >= 70 check sits on top, it grabs the win first, prints C, and the A branch never gets evaluated. The lesson: order your conditions from strictest to loosest. Python doesn't know which check you "meant" to be more important — it just runs the first one that opens.
The second big intuition is truthiness. Python doesn't require you to write an explicit comparison every time. You can drop almost any value directly into an if, and Python will decide for you whether it counts as true or false:
name = ""
if name:
print(f"Hello, {name}")
else:
print("No name provided")
name is an empty string, which Python treats as falsy — no comparison needed. The values that count as falsy are worth memorizing once:
| Falsy values | Everything else |
|---|---|
False, None, 0, "", [], {} |
Truthy |
You can verify this yourself with bool():
print(bool("")) # False
print(bool("hi")) # True
print(bool(0)) # False
print(bool([1])) # True
The third intuition, and the one that trips up almost every beginner at least once, is the difference between = and ==. A single equals sign assigns a value; a double equals sign compares two values.
x = 5
if x == 5: # comparison — correct
print("Matches!")
Write if x = 5: instead, and Python throws a SyntaxError immediately rather than silently doing the wrong thing. That's actually a kindness — some languages let this slide and turn it into a runtime bug that's brutal to track down.
Brute Force Solution
There isn't really a "brute force vs optimal" split for conditionals the way there is for an algorithm problem — but there is a naive habit beginners fall into that's worth calling out: nesting everything, even when it isn't necessary.
logged_in = True
is_admin = False
if logged_in:
if is_admin:
print("Admin dashboard")
else:
print("User home")
else:
print("Please log in")
Idea: wrap every additional condition inside another if, one level deeper each time.
Advantages: each level of nesting can have completely separate handling — useful when the branches genuinely diverge (e.g., different error messages, different follow-up logic).
Disadvantages: the code drifts further and further to the right, and once you're four or five levels deep, it's hard to trace which condition is actually being checked. This is sometimes called the "arrow anti-pattern."
Time complexity: O(1) — a fixed number of comparisons regardless of nesting depth. Space complexity: O(1) — no extra memory is used; nesting only affects readability, not performance.
Optimal Solution
When the branches don't need separate handling — when you're really just asking "is the answer yes to both of these?" — combining conditions with and is cleaner:
logged_in = True
is_admin = False
if logged_in and is_admin:
print("Admin dashboard")
elif logged_in:
print("User home")
else:
print("Please log in")
This produces the exact same behavior as the nested version above, but it's flatter and easier to scan. The rule of thumb: reach for and when the answer is a plain yes-or-both; only nest when each layer truly needs its own distinct handling (different error messages, different logging, different cleanup steps, etc.).
Here's a quick reference for combining conditions:
| Operator | Meaning | Example | Result |
|---|---|---|---|
and |
both sides must be true | 20 < 25 and 25 < 30 |
True |
or |
at least one side true | 25 > 100 or 25 < 30 |
True |
not |
flips the result | not (25 > 30) |
True |
age = 25
if age > 20 and age < 30:
print("Comfortable age range")
Python Code
Here's a complete, production-quality example that ties if/elif/else, truthiness, and combined conditions together in one realistic function:
def classify_user(name: str, age: int, is_admin: bool = False) -> str:
"""Return an access-level message based on name, age, and admin status."""
if not name:
return "No name provided"
if is_admin and age >= 18:
return f"Welcome, admin {name}"
elif age >= 18:
return f"Welcome, {name}"
else:
return f"Sorry {name}, minors are not allowed"
Code Walkthrough
def classify_user(name: str, age: int, is_admin: bool = False) -> str:— defines a function with type hints;is_admindefaults toFalseif not provided.if not name:— relies on truthiness. An empty string is falsy, sonot namebecomesTrue, catching missing input before anything else runs.if is_admin and age >= 18:— a combined condition. Both sides must beTruefor this branch to trigger, avoiding a nestedifinside anif.elif age >= 18:— only checked if the first condition failed, so this catches adults who aren't admins.else:— the final catch-all for anyone under 18.
Dry Run
Let's trace classify_user("Kai", 25, is_admin=True):
nameis"Kai", which is truthy, sonot nameisFalse— skip the first branch.is_adminisTrueandage >= 18(25 >= 18isTrue) — both sides ofandareTrue, so the condition isTrue.- Python enters this branch, returns
"Welcome, admin Kai", and stops. Theelifandelseare never evaluated.
Now trace classify_user("", 30):
nameis"", which is falsy —not nameisTrue.- Python immediately returns
"No name provided"without ever checking age.
Complexity Analysis
Time complexity: O(1). Every branch is a constant number of comparisons — Python checks conditions top to bottom and stops at the first match, so the work doesn't grow with input size.
Space complexity: O(1). No additional data structures are created; only the existing variables are read.
These bounds hold regardless of how many elif branches you add, because each one is a simple boolean check, not a loop or recursive call.
Alternative Solutions
For simple value-to-value mapping (rather than range checks), Python 3.10+ offers match/case as a structurally different alternative:
def day_type(day: str) -> str:
match day:
case "Saturday" | "Sunday":
return "Weekend"
case _:
return "Weekday"
match shines when you're comparing one value against several exact options or patterns. It's not a replacement for range checks like age >= 18 — if/elif/else remains the right tool whenever you're dealing with comparisons, boolean logic, or truthiness rather than exact matches.
Edge Cases
- Empty input: an empty string, list, or dict is falsy — make sure that's actually the behavior you want before relying on it implicitly.
- Zero as a valid value:
0is falsy, soif quantity:will skip a legitimate order of zero items the same way it skips "no value." Useif quantity is not None:when zero is meaningful. - Boundary values:
age >= 18includes 18;age > 18doesn't. Off-by-one mistakes here are extremely common — double-check whether your boundary should be inclusive. - Overlapping conditions in the wrong order: as shown earlier, a loose condition placed before a strict one will silently swallow it.
Nonevs falsy:None,0, and""are all falsy, but they mean very different things. Don't conflate "no value was given" with "the value is zero."
Common Mistakes
- Using
=instead of==inside a condition — Python raises aSyntaxErrorfor this, which is actually a safety net compared to languages that don't. - Ordering loose conditions before strict ones, causing an early
elifto swallow cases meant for a later branch. - Relying on truthiness when zero is a valid value, silently treating
0the same as "missing." - Nesting when
andwould be flatter and more readable, making the logic harder to follow than necessary. - Forgetting the colon or misindenting the block, which either raises a
SyntaxErroror — worse — silently changes which lines belong to which branch. - Chaining unrelated
ifstatements instead ofelif, which causes multiple branches to run when only one was intended.
Interview Questions
- What's the difference between using multiple
ifstatements versuselif? - Why does Python evaluate elif conditions in order, and why does that matter?
- What values are falsy in Python, and why might that be useful (or dangerous)?
- How would you rewrite a deeply nested
ifchain to be flatter? - What's the difference between
and/orshort-circuiting versus evaluating both sides?
Similar Problems
- LeetCode 1: Two Sum — relies on conditional checks inside a loop to test whether a complement exists.
- LeetCode 20: Valid Parentheses — built almost entirely on branching logic to decide what to do with each character.
- LeetCode 121: Best Time to Buy and Sell Stock — uses conditionals to track running minimums and maximums.
- LeetCode 217: Contains Duplicate — a simple conditional check against a seen-values set.
Each of these problems assumes you're fluent enough with if/elif/else that the branching logic isn't the bottleneck — the algorithm is.
Key Takeaways
ifruns code when a condition is true;elsecatches everything else;elifstacks additional choices in between.- Python checks conditions top to bottom and stops at the first
True— order your branches strict to loose. - Empty strings, empty collections,
0, andNoneare all falsy; everything else is truthy. =assigns,==compares — Python will error on the former inside a condition, which is a helpful guardrail.- Prefer
and/or/notto flatten logic over nesting, unless each layer genuinely needs separate handling.
Watch the Video
This lesson is easiest to absorb by watching it in motion — seeing each branch execute live makes the "first true wins" rule click. {LINK}
About the Series
This is Lesson 6 of the Daily Python series, where each video builds one core concept at a time — no shortcuts, no assumed knowledge. If you're following along from Lesson 1, conditionals are the piece that turns straight-line scripts into programs that actually respond to the world around them.
Call To Action
If this lesson helped things click, subscribe on YouTube so you don't miss the next one, and subscribe to the Substack for the written breakdown delivered straight to your inbox. Drop a comment with the condition or bug that's tripped you up before — chances are someone else has hit the exact same one. And if you know someone learning Python right now, send this their way.
The solution
logged_in = True
is_admin = False
if logged_in:
if is_admin:
print("Admin panel")
else:
print("User home")
else:
print("Please log in")Ready to try it yourself? Solve General problems with instant feedback in the practice sandbox.
Practice now →


