Fundamentals
if, elif and else in Python: Several Ranges and Nested Conditions
Learn to choose among three or more paths with if, elif and else in Python, to order the ranges and to nest conditions without getting lost in indentation.
By Prof. Rodrigo Faustino · Updated on · 13 min read
Metrics for this article
- Words
- 2,433
- Characters
- 13,125
- Reading time
- ~13 min
The elif lets the program choose among three or more paths in a single structure. It works like an "otherwise, if": Python tests the first condition, then the second, then the third, and runs the block of the first one that is true, ignoring all the others. The else at the end covers whatever is left. When a decision only makes sense after another one, the block can contain an if inside it, and this is called a nested condition.
The previous article introduced the if and the else, which choose between two paths and raise the first question for anyone programming: indentation. This one shows how to grow to more paths without writing a pile of ifs that trample each other, why the order of the conditions changes the result, how to nest safely and which problems show up most in classes.
The problem: two options are not enough
A school converts a grade from zero to ten into a letter: from 9 up, A; from 7 to less than 9, B; from 6 to less than 7, C; below that, D. That is four paths, and the if with else only tells two apart. The temptation is to stack ifs, one per letter, and the section on order shows what happens when you do that. For now, it is worth remembering what the decision needs: a list of questions, in order, in which the first "yes" decides and the rest stop mattering.
That is exactly what elif does. The complete structure has an if at the beginning, as many elifs as needed and, if you like, an else at the end.
From the syllabus to a planned semester
- Teaching plan and calendar built automatically
- Class diary ready to paste into SIGA
- Slides and exercise lists with answer keys
Free Community edition · Windows
The elif: the ladder of tests
for nota in (10, 9, 8.5, 7, 6, 5.99, 0):
if nota >= 9:
conceito = "A"
elif nota >= 7:
conceito = "B"
elif nota >= 6:
conceito = "C"
else:
conceito = "D"
print(nota, conceito)The output is 10 A, 9 A, 8.5 B, 7 B, 6 C, 5.99 D and 0 D. The for goes through the grades, one at a time, and the if and elif block runs for each one. Notice the limits: the grade 9 is an A, and the grade 7 is a B, because the test is >=. The grade 5.99 stays at D, even though it is a hundredth away from C. Each condition only needs to state the lower limit, because the upper limit has already been handled by the previous tests: when the program reaches nota >= 7, it already knows the grade is less than 9, otherwise the first test would have decided.
Each elif has the same anatomy as the if: the word, the condition, the colon and the indented block. The else still takes no condition and is still optional. You can have an if with elif and without else, and in that case, if no test is true, no block runs and the program moves on.
Three loose ifs are not an if with elif
The most common confusion for those learning is to think that writing three ifs in a row is the same as writing if, elif and elif. It is not. Each new if is an independent question, and all of them are asked.
nota = 9.5
if nota >= 9:
print("A")
if nota >= 7:
print("B")
if nota >= 6:
print("C")
print("---")
if nota >= 9:
print("A")
elif nota >= 7:
print("B")
elif nota >= 6:
print("C")
print("---")
if nota >= 6:
print("C")
elif nota >= 7:
print("B")
elif nota >= 9:
print("A")The output is A, B, C, a separator line, A, another separator and C. In the first snippet, the grade 9.5 satisfies all three conditions, and each loose if runs its block: the program answers three times. In the second, the elif does what is expected, and only the first True wins. In the third, the order is inverted: the condition nota >= 6 is true for almost everything, so it captures the grade 9.5 before nota >= 9 has a chance, and the letter A becomes unreachable. None of the three snippets gives an error. Only one gives the right answer.
The rule of thumb that solves almost everything: write the conditions from the most restrictive case to the least restrictive. In the ladder of grades, from 9 downwards. In a ladder of increasing temperatures, the logic is inverted, and the first condition is the one with the smallest value:
for t in (12, 18, 25, 26, 31, 40):
if t < 18:
print(t, "cold")
elif t < 26:
print(t, "pleasant")
elif t < 32:
print(t, "hot")
else:
print(t, "very hot")The output goes from 12 cold to 40 very hot, and the limits end up in the right places: 18 is pleasant and 26 is hot, because the tests are < and the value equal to the limit falls in the range above. What matters in both examples is the same idea: the ranges touch without gaps and without overlap, and each value falls in exactly one of them.
A new if restarts the conversation
An if, elif, else chain ends where the indentation goes back to the margin with a line that is neither elif nor else. The if that appears afterwards is another chain, unrelated to the previous one.
x = 7
if x > 3:
print("greater than 3")
elif x > 5:
print("greater than 5")
if x > 5:
print("greater than 5 (new if)")
elif x > 100:
print("huge")
else:
print("neither")The output is greater than 3 and greater than 5 (new if). In the first chain, x > 3 already decided and the elif x > 5 was not even looked at. The second chain starts from scratch with the if x > 5, and that is why the 7 gets both messages. If the intention was a single chain, the second if should have been an elif.
Nested conditions
Sometimes the second question only makes sense after the first. To know whether someone can drive, you only ask about the license if the person is already of legal age. That is written with one if inside another, one level of indentation further in.
idade = 20
tem_carteira = False
if idade >= 18:
if tem_carteira:
print("can drive")
else:
print("needs to get a license")
else:
print("underage")
if idade >= 18 and tem_carteira:
print("can drive")
elif idade >= 18:
print("needs to get a license")
else:
print("underage")Both versions give the same output, needs to get a license twice. The first nests: the question about the license only happens inside the block for those of legal age, and each else stays at the indentation of the if it belongs to. The second is flat: it uses and and elif. Which one is better depends on the problem. Nesting makes the dependency clearer ("I only ask this if that is true"), and the flat version tends to be shorter when the conditions are on the same level. More than three levels of indentation is, in general, a sign that it is worth reorganizing.
Which if does the else belong to?
With nested ifs, this is the question that confuses the most, and the answer is always the same: to the if that has the same indentation.
a = 5
b = 0
if a > 3:
if b > 3:
print("x")
else:
print("outer else")
print("---")
if a > 3:
if b > 3:
print("x")
else:
print("inner else")
print("end")In the first part, the else is at the margin, aligned with the if a > 3. Since a > 3 is true, the outer else does not run, and nothing is printed, not even x, because b > 3 is false. In the second, the else was indented one level and now belongs to the if b > 3: the output is inner else and end. It is the same text with a difference of four spaces, and the program now answers a different question.
What changes on the ESP32
The structure and the rules of elif are the same in MicroPython. Two points call for care on the board. The first is the precision of the float, which with 32 bits does not tell very close numbers apart:
print(5.9999999 >= 6, 5.9999999, 5.99999 >= 6, 5.99999)
nota = 5.9999999
if nota >= 6:
print("approved")
else:
print("failed")In the simulator, the output is True 6.0 False 5.99999 and approved: the value 5.9999999 is rounded to 6.0 at the moment the program reads it, and the comparison with 6 passes. In Python on the computer, with the 64-bit float, 5.9999999 >= 6 is False and the program would answer failed. With typed grades this hardly matters, but a calculated average or a sensor reading that sits a fraction away from the limit can fall into one range or the other depending on the type of float. When a decision really matters, leave a margin between the ranges or work with integers.
The second point is the most common use of elif in hardware: converting a reading into levels. The ESP32's analog converter returns values from 0 to 4095, and a light sensor can become three states:
for valor in (0, 500, 1500, 3000, 4095):
if valor < 1000:
nivel = "dark"
elif valor < 2500:
nivel = "dim"
else:
nivel = "bright"
print(valor, nivel)The output is 0 dark, 500 dark, 1500 dim, 3000 bright and 4095 bright. Real readings fluctuate, and when one of them sits right at a limit the state flickers between two levels. The solution, with a margin on each side, is one of the subjects of the article on ADC and attenuation.
The messages for the typical elif errors also differ:
| Error | Simulator (MicroPython) | Python on the computer |
|---|---|---|
else if x > 3: (written as in other languages) | SyntaxError: invalid syntax | SyntaxError: expected ':' |
elseif x > 3: | SyntaxError: invalid syntax | SyntaxError: invalid syntax |
elif after the else | SyntaxError: invalid syntax | SyntaxError: invalid syntax |
elif without an if before it | SyntaxError: invalid syntax | SyntaxError: invalid syntax |
elif x > 3 without the colon | SyntaxError: invalid syntax | SyntaxError: expected ':' |
elif: without a condition | SyntaxError: invalid syntax | SyntaxError: invalid syntax |
else x > 3: (else does not accept a condition) | SyntaxError: invalid syntax | SyntaxError: expected ':' |
In the simulator, they all become the same invalid syntax, and the line number is what helps. The classic example from those coming from C or JavaScript:
x = 5
if x > 9:
print("a")
else if x > 3:
print("b")Traceback (most recent call last):
File "main.py", line 4
SyntaxError: invalid syntaxPython has no else if. The word is a single one, elif, and it goes together with the condition and the colon.
The AI that remembers your life and lives on your computer
- Long-term memory with the source of every answer
- Works offline: your data stays on your PC
- Reads PDFs, slides, photos and meeting recordings
Essential plan free forever
In the classroom: where elif tends to trip people up
The problems below repeat in almost every class that reaches this subject. Each one gives a program that runs, which makes the cause hard to find.
Several ifs in place of an elif
The program asks for the letter grade and answers three times for the same grade, or prints an "approved" and a "failed" together. The cause is the one the figure with the three versions shows: each loose if is a new question. The question to ask is whether the answers are mutually exclusive. If so, it is an elif.
The ranges in the wrong order
The letter A never appears, because the test nota >= 6 comes before nota >= 9. It is an error that passes every test with low grades and only shows up when someone with a high grade uses the program. Writing the list of ranges on paper, from the most restrictive to the least, before typing avoids the problem.
The limit with the wrong sign
With nota > 6 in place of nota >= 6, whoever got exactly 6 falls into D. It is the kind of defect that only appears at the boundary value, and the defense is to always test the limits: the value itself, one above and one below.
Comparing with several values using or
if conceito == "A" or "B" does not compare with A and with B. Remember the x == 1 or 2 from the article on logical operators? The text "B" alone is always true, and the condition passes for every letter. The right form is to repeat the variable, conceito == "A" or conceito == "B", or to use in: conceito in ("A", "B").
The pyramid of ifs
Five or six levels of nested if, each time further to the right, with the else way down at the end of the page and nobody remembering which question it answers. Almost always you can flatten it: an and joins two questions of the same level, and an elif replaces a nesting that only serves to choose among alternatives.
The lost else
The else indented one level too many or too few, and the program starts answering the wrong question, as in the figure with the two versions. The check is visual: the else and the if it belongs to start at the same column.
The final else is missing
The program works for everything that was foreseen, and for what nobody foresaw it simply does nothing: no message, no error. In a sign-up form, the user types an option that does not exist and the program goes silent. An else with a message such as "invalid option" turns the silence into a clue.
Exercise: what kind of triangle is this?
Given the three sides of a triangle, the program must say whether it is equilateral (three equal sides), isosceles (two equal) or scalene (all different). But first you need to know whether the sides form a triangle: each side must be smaller than the sum of the other two. It is a decision with two layers, and that is where nesting helps.
for lados in ((3, 3, 3), (3, 3, 5), (3, 4, 5), (1, 2, 10), (2, 2, 4)):
a, b, c = lados
if a < b + c and b < a + c and c < a + b:
if a == b == c:
print(lados, "equilateral")
elif a == b or b == c or a == c:
print(lados, "isosceles")
else:
print(lados, "scalene")
else:
print(lados, "not a triangle")The output has five lines: (3, 3, 3) equilateral, (3, 3, 5) isosceles, (3, 4, 5) scalene, (1, 2, 10) not a triangle and (2, 2, 4) not a triangle. The last case deserves attention: the sides 2, 2 and 4 have two equal, but 4 is not smaller than 2 plus 2, and an if that only looked at equality would call it isosceles. The outer question filters, and the inner ladder classifies. Notice the order of the inner ladder: the equilateral case, the most restrictive, comes first, because an equilateral triangle also has two equal sides and would be captured by the isosceles if that one came first. To read the sides from the keyboard, replace the first line with three int(input()), as in the article on type conversion.
Frequently asked questions
How many elifs can I use?
As many as you need. But a ladder with more than five or six steps usually calls for another structure, and the next article in the series shows an alternative with dictionaries for the case in which each step is just an equality comparison.
Is the else mandatory at the end?
No, but it is a good safety net. Without it, a value that does not fit any range passes through doing nothing, and the defect takes a while to show up.
What is the difference between elif and a new if?
The elif belongs to the chain that the if opened and is only evaluated if all the previous conditions are false. A new if opens another chain, and is always evaluated.
Can I put an elif inside a nested block?
You can. Each nested if can have its own elif and else, and they stay at the same indentation as the if they belong to. The indentation is what says who is who.
Does Python have a switch?
Not the way C or Java do. To choose among many exact values, the way out is the elif ladder or a dictionary, which the next article explains.
Where to go next
The Logic with Python track has challenges with several ranges. Positive or Negative asks for more than two answers, Day of the Week and Season of the Year ask for ladders with limits, and Calculator with Menu chooses the operation from a typed option. If the indentation is still getting in the way, reread the article on if and else, which gathers the most common indentation errors.
The next subject is choosing among many options: when the elif ladder gets too long, what a dictionary solves better and why MicroPython has no match and case.