Skip to Content
If-Else

If and Else

Conditionals decide which code runs from whether something is true or false. Python uses if, elif, and else; one condition is checked and one branch runs. Truthiness and short-circuit behavior cause most of the gotchas, so they’re worth getting straight.

The if Statement

The simplest form runs a block only when a condition is true:

if condition: # block runs only when condition is true statement_1 statement_2

The condition can be any expression. Python evaluates it in a Boolean context and runs the block when the result is truthy. A colon after the condition is required; the block is everything indented under the if. The first line that isn’t indented more ends the block.

x = 6 if x > 4: print("x is greater than 4") # Output: x is greater than 4

If the condition is false, the block is skipped and execution continues after it.

if and else

else runs a different block when the condition is false. Exactly one of the two blocks runs.

if condition: # when condition is true block_a else: # when condition is false block_b
score = 8 if score >= 6: print("Pass") else: print("Fail") # Output: Pass

The else has to align with the if it belongs to. There’s no condition on else; it just means “when the if condition is false.”

if, elif, and else

More than two outcomes? Use elif (else-if). Python evaluates the conditions in order; the first one that’s true runs its block and the rest are skipped. else, if present, runs only when every if and elif condition is false.

if condition_1: block_1 elif condition_2: block_2 elif condition_3: block_3 else: block_else

At most one block runs. When it’s done, execution continues after the whole chain.

status_code = 4 if status_code == 2: label = "pending" elif status_code == 4: label = "active" elif status_code == 6: label = "done" else: label = "archived" # label is "active"

Order matters. If condition_1 is true, condition_2 and condition_3 are never evaluated, so put the most specific or most likely cases first when that affects correctness or performance.

Condition Expressions

Conditions are built from comparisons and logical operators.

Comparison Operators

OperatorMeaningExample
==Equal tox == 6
!=Not equal tox != 4
<Less thanx < 8
<=Less or equalx <= 8
>Greater thanx > 2
>=Greater or equalx >= 2
isSame objectx is None
is notNot same objectx is not None
a, b = 4, 8 a == 4 # True a != b # True a < b # True a >= 4 # True

Identity vs equality: is and is not compare identity: whether two names refer to the same object in memory. Use them for None (and sometimes singletons like True/False). For values (numbers, strings, collections), use == and !=. if x == None works, but if x is None is the usual style; for “not None” use if x is not None.

Logical Operators

OperatorMeaningExample
andBoth truea > 2 and a < 10
orAt least one truea < 2 or a > 8
notNegatenot (a == 4)
x = 6 x > 2 and x < 10 # True x < 4 or x > 8 # False not (x == 4) # True

Logical operators return one of the operands (see Short-circuit evaluation). In an if condition that value is just treated as truthy or falsy.

Chained Comparisons

Python lets you chain comparisons; each middle value is shared and the expression is evaluated once per comparison.

x = 6 2 < x < 10 # same as (2 < x) and (x < 10) → True 2 < x <= 6 # True

That’s equivalent to and-ing the comparisons. Chaining is readable and avoids repeating the variable.

Truthiness

In conditions, any value is allowed; Python treats it as truthy or falsy. That shows up a lot in interviews and in subtle bugs.

Falsy values (the condition is treated as false):

ValueType
Falsebool
NoneNoneType
0int
0.0float
""str (empty string)
[]list (empty)
()tuple (empty)
{}dict (empty)
set()set (empty)

Everything else is truthy: non-zero numbers, non-empty strings, non-empty collections, and most other objects.

if []: print("list") # not run if [2, 4]: print("list") # runs if "": print("str") # not run if "x": print("str") # runs if 0: print("zero") # not run if 2: print("two") # runs if None: print("None") # not run

Watch out: 0 and empty containers are falsy. if items: means “at least one”; if not items: means “empty.” Prefer that over len(items) == 0. The string "False" is truthy; only the Boolean False is falsy.

Nested Conditionals

if and elif blocks can contain more ifelifelse chains. Indentation defines which if an else belongs to; else attaches to the nearest if at the same indentation level.

x = 6 y = 4 if x > 4: if y > 2: print("both large") else: print("x large, y not") else: print("x not large") # Output: both large

Deep nesting gets hard to read. elif, early returns in functions, or pulling logic into helpers usually makes the flow clearer.

Conditional Expression (Ternary)

Pick one of two values with a conditional expression: value_when_true if condition else value_when_false. It’s an expression, so it fits anywhere a value goes: assignments, arguments, return values.

x = 6 label = "even" if x % 2 == 0 else "odd" # "even"

Only one branch is evaluated. Good for short, clear choices; for anything longer, a normal ifelse block is easier to read.

a, b = 4, 8 max_val = a if a >= b else b # 8

Short-Circuit Evaluation

and and or short-circuit: they stop as soon as the result is clear. and returns the first falsy value or the last; or returns the first truthy value or the last. So you get one of the operands back, not always True or False. In an if that’s still treated as truthy or falsy.

x = 0 y = 4 # x is falsy; (x and y) never evaluates y, result is 0 if x and y: print("both") # not run # x is falsy; (x or y) evaluates y, result is 4 (truthy) if x or y: print("at least one") # runs

Using or for a default only works when the real value is never falsy. user_input or "Anonymous" is fine. cache or 0 is wrong when 0 is a valid cached value; use cache if cache is not None else 0 (or similar) when “missing” isn’t the same as a valid value.

Style and Clarity

Returning early from a function often reads better than one deep ifelifelse. Use elif when the cases are mutually exclusive; use nested if when the inner check only applies when the outer one is true. Prefer positive conditions (if valid: instead of if not invalid:) when it’s clearer.

Tricky Behaviors

Order below matches the main content: conditions and comparisons first, then truthiness, then elif/else, then logical operators and short-circuit, then the ternary form.

= in a condition

= assigns, == compares. if x = 4 is a syntax error. Use == (or is for identity). The walrus operator := is for places where an expression is allowed (e.g. while), not for if conditions.

x = 4 if x == 6: # correct print("six") # if x = 6: # wrong; syntax error

is vs == for None and for integers

Use is / is not for None; style guides prefer it over ==. For numbers, use ==. is checks identity; small ints are cached in CPython so x is 4 can seem to work, but it’s not something to rely on.

Truthiness: more than True and False

Only a fixed set is falsy: False, None, 0, 0.0, "", and empty [], (), {}, set(). Everything else is truthy. The string "False" and the list [0] are truthy; “looks like a flag” doesn’t make it falsy.

Falsy isn’t False

0, "", [] are falsy in conditions but aren’t the same object as False. 0 == False is True; 0 is False is False. Prefer if items: over comparing to False for collections.

elif order: first match wins

Conditions are checked top to bottom; the first true one runs and the rest are skipped. Put the most specific or likely case first when it matters.

and / or return an operand, not always a bool

and returns the first falsy value or the last; or returns the first truthy value or the last. So 2 or 4 is 2, 0 or 4 is 4. In an if that’s fine; in assignments you get the actual value, not necessarily True/False.

Defaults with or when 0 or "" is valid

cache or 0 treats both None and 0 as “use default.” If 0 is a valid value, that’s wrong. Use cache if cache is not None else 0 (or similar) when the sentinel isn’t the same as a valid value.

Chained comparisons and evaluation order

In a < b < c, b is evaluated once. If b had side effects you’d see them once, not twice.

else on a for or while loop

Loop else runs when the loop finishes without break. It doesn’t mean “the iterable was empty.” Easy to mix up with ifelse.

Conditional expression: only one branch runs

In a if cond else b, only one of a or b is evaluated. The other branch’s side effects don’t run.

Interview Questions

Order follows the main content: conditions and comparisons, then truthiness, then elif/else, then logical operators and short-circuit, then the ternary form.

What happens if you write “if x = 4”?

SyntaxError. Assignment isn’t allowed there. Use == to compare.

What is the difference between == and is?

== compares values; is compares identity (same object). Use == for numbers and most values. Use is for None; PEP 8 recommends it. For small integers, is can seem to work because of caching; stick to ==.

Why use “if x is None” instead of “if x == None”?

is means “this exact object”; == can be overridden. For None, is is clearer and preferred.

Which values are falsy in Python?

False, None, 0, 0.0, "", and empty [], (), {}, set(). Everything else is truthy. So "False" and [0] are truthy.

What does “if 0:” do? What about “if [0]:”?

if 0: is false (block skipped). if [0]: is true; the list isn’t empty, so it’s truthy. For collections, “empty or not” matters, not what’s inside.

Why is “if items:” preferred over “if len(items) > 0”?

Shorter and idiomatic. Empty collections are falsy, so if items: means “at least one.” Same for if not items: instead of len(items) == 0.

When does the else clause on a for or while loop run?

When the loop finishes without break. If you break out, the else block is skipped. So else means “completed without breaking.”

When would you use elif instead of nested if?

elif when the cases are mutually exclusive at the same level (one variable, several values). Nested if when the inner check only makes sense when the outer one is true (e.g. “if logged in, then if admin”).

What do and and or return?

One of the operands. and returns the first falsy or the last; or returns the first truthy or the last. So 2 or 4 is 2. In conditions that value is treated as truthy or falsy.

What is short-circuit evaluation?

and and or stop as soon as the result is clear. If the left of and is falsy, the right isn’t run. If the left of or is truthy, the right isn’t run. That lets you write things like x and x.method() safely.

When is “x or default” a bug?

When a valid value is falsy (0, "", []). Then x or default overwrites it. Use something like x if x is not None else default when “missing” isn’t the same as a valid value.

How do you choose between a conditional expression and an if-else block?

Use a if cond else b for short, single-value choices. Use an ifelse block when a branch has several statements or is easier to read on multiple lines.

When there are many discrete branches (e.g. several string or numeric literals), Python 3.10+ matchcase can make long ifelifelse chains clearer. For two or three outcomes, ifelifelse is still the usual choice.

In practice: use ifelifelse for branching, == for values and is for None, and truthiness for “has items” or “is set.” Don’t use = in conditions, and remember loop else (runs when you don’t break) is not the same as ifelse.

Last updated on